ListViewの手のひらのアイテムでイベントが発生しました
-
21-12-2019 - |
質問
UserControl
イベントに加入しているGrid
を持つHolding
を持ちます。問題は、Holding
イベントがターゲットとされている項目がListView
内の他の項目に対して発行されることです。ところでDataTemplateとしてコントロールを使用しています。
<ListView ItemsSource="{Binding ...}" Margin="0, 0, 0, 0">
...
<ListView.ItemTemplate>
<DataTemplate>
<local:MyUserControl/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
.
ユーザ制御コード後ろ:
private bool isDescriptionVisible = false;
private void Grid_Holding(object sender, HoldingRoutedEventArgs e)
{
if (!isDescriptionVisible)
{
DescriptionFadeIn.Begin();
isDescriptionVisible = true;
}
}
private void Grid_Tapped(object sender, TappedRoutedEventArgs e)
{
if (isDescriptionVisible)
{
DescriptionFadeOut.Begin();
isDescriptionVisible = false;
}
}
.
ユーザ制御内容:
<Grid.Resources>
<Storyboard x:Name="FadeIn">
<DoubleAnimation Storyboard.TargetProperty="Opacity" Storyboard.TargetName="DescriptionLayer"
Duration="0:0:0.3" To=".8"/>
</Storyboard>
<Storyboard x:Name="FadeOut">
<DoubleAnimation Storyboard.TargetProperty="Opacity" Storyboard.TargetName="DescriptionLayer"
Duration="0:0:0.3" To="0"/>
</Storyboard>
</Grid.Resources>
<Grid Margin="0, 0, 0, 48" Holding="Grid_Holding" Tapped="Grid_Tapped">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Image Source="{Binding Img}" Stretch="UniformToFill" Height="240" Width="450"/>
<Grid x:Name="DescriptionLayer" Background="Black" Opacity="0">
<TextBlock Text="{Binding Description}" FontSize="16" TextWrapping="Wrap" Margin="0, 9, 0, 0" MaxHeight="170" TextTrimming="CharacterEllipsis"/>
</Grid>
<StackPanel Grid.Row="1" Margin="12">
<TextBlock Text="{Binding Author}" FontSize="16"/>
<TextBlock Text="{Binding Title}" FontSize="18"/>
</StackPanel>
</Grid>
.
DataTemplateに含まれているアイテムでストーリーボードを使用できませんでしたので、その内容をUserControlに使用することを強制しました。
この問題は仮想化と関係がある必要がありますか?どうすればいいですか?
代替案は行います。
更新:
その他の投稿は、リサイクルモードがアイテムを再利用することを提案した。私は追加しました
私のListViewへのVirtualizingStackPanel.VirtualizationMode="Standard"
しかし、問題は驚くほど持続します。
今度は、他の項目が同じ不透明度の値を繰り返すのを防ぐ方法を理解する必要があります(ストーリーボードを介して設定されているため、データバウンドではありません)。
更新2 :
現在表示されているアイテムを保持しているときにフェードインすると、視聴不能になると完全に消えます。
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
. 解決
私はあなたがここでやろうとしているのを目指しているのが好きです。タッチスクリーンデバイスの場合、MouseOver
イベントはありませんので、UIをめちゃくちゃにすることなくいくつかの追加情報を表示したい場合の方法の1つです。
しかし、すべてのUIロジックとアニメーションをカプセル化する再利用可能なBehavior
を作成するには、はるかにクリーンなソリューションがあります。
これを行うために、最初に参照Behaviors SDK (XAML)
を含める必要があります。
Behavior
の実装は簡単です。 AssociatedObject
は、タッチイベントを受信し、次に説明Grid
インスタンスを取得するためにDependencyProperty
TextBlockName
を作成する必要があります。インスタンスがあると、C#。
public class ShowHideDescriptionBehavior : DependencyObject, IBehavior
{
public string TextBlockName
{
get { return (string)GetValue(TextBlockNameProperty); }
set { SetValue(TextBlockNameProperty, value); }
}
// Using a DependencyProperty as the backing store for TextBlockName. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TextBlockNameProperty =
DependencyProperty.Register("TextBlockName", typeof(string), typeof(ShowHideDescriptionBehavior), new PropertyMetadata(string.Empty));
public DependencyObject AssociatedObject { get; set; }
public void Attach(DependencyObject associatedObject)
{
this.AssociatedObject = associatedObject;
var panel = (Panel)this.AssociatedObject;
panel.Holding += AssociatedObject_Holding;
panel.Tapped += AssociatedObject_Tapped;
}
private void AssociatedObject_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
{
var animation = new DoubleAnimation
{
Duration = TimeSpan.FromMilliseconds(300),
To = 0
};
Storyboard.SetTarget(animation, this.DescriptionTextBlock);
Storyboard.SetTargetProperty(animation, "Opacity");
var storyboard = new Storyboard();
storyboard.Children.Add(animation);
storyboard.Begin();
}
private void AssociatedObject_Holding(object sender, Windows.UI.Xaml.Input.HoldingRoutedEventArgs e)
{
var animation = new DoubleAnimation
{
Duration = TimeSpan.FromMilliseconds(300),
To = 0.8
};
Storyboard.SetTarget(animation, this.DescriptionTextBlock);
Storyboard.SetTargetProperty(animation, "Opacity");
var storyboard = new Storyboard();
storyboard.Children.Add(animation);
storyboard.Begin();
}
private TextBlock _descriptionTextBlock;
private TextBlock DescriptionTextBlock
{
get
{
if (_descriptionTextBlock == null)
{
var panel = (Panel)this.AssociatedObject;
// todo: add validation
_descriptionTextBlock = (TextBlock)panel.FindName(this.TextBlockName);
}
return _descriptionTextBlock;
}
}
public void Detach()
{
var panel = (Panel)this.AssociatedObject;
panel.Holding -= AssociatedObject_Holding;
panel.Tapped -= AssociatedObject_Tapped;
}
}
.
このTextBlock
は、Behavior
の最上位のDataTemplate
に接続できます。もう包むためのGrid
を必要としないことに注意してください。
また、UserControl
の背景色があるため、タッチイベントを受信できるようにしてください。私がした最後のことは、Grid
のListView
をItemContainerStyle
に変更することでしたので、HorizontalContentAlignment
が右側にずっと伸びるようにします。
<Page.Resources>
<DataTemplate x:Key="GroupTemplate">
<Grid Background="Transparent" Margin="12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Interactivity:Interaction.Behaviors>
<local:ShowHideDescriptionBehavior TextBlockName="Description" />
</Interactivity:Interaction.Behaviors>
<Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}" Width="110" Height="110">
<Image Source="{Binding Img}" Height="110" Width="110"/>
</Border>
<StackPanel Grid.Column="1" Margin="10,0,0,0">
<TextBlock Text="{Binding Author}" Style="{StaticResource TitleTextBlockStyle}"/>
<TextBlock x:Name="Description" Opacity="0" Text="{Binding Description}" Style="{StaticResource CaptionTextBlockStyle}" TextWrapping="NoWrap"/>
</StackPanel>
</Grid>
</DataTemplate>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" DataContext="{Binding Source={StaticResource SampleDataSource}}">
<ListView ItemTemplate="{StaticResource GroupTemplate}" ItemsSource="{Binding Groups}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>
</Grid>
. 他のヒント
私は回避策を見つけました。 DescriptionLayerOpacity
というプロパティをMy Modelに追加し、私のViewModelの0
に新しい項目を追加しているときにそれを既定値に設定しました。
ソースプロパティ(ObservableCollection
)を変更するための2方向バインディングを追加して、ストーリーボードによって行われた変更で更新されるようにしてください。
<Grid ... Opacity="{Binding DescriptionLayerOpacity, Mode=TwoWay}">
<TextBlock .../>
</Grid>
.
Nutshellでは、ListViewの他の項目で繰り返されるのを防ぐために、すべてのUserControlのデータをデータバインドしなければなりませんでした。
これは本当に優雅な解決策ではなく、完全にテストされていません。実際の解決策が見つかるまで、これは十分です。
アップデート:完全に機能しない
私は最近、他の項目が選択されている場合には何らかのアイテムが応答しないことを発見しました。これらの項目を応答するには、TAP + HOLDイベントの前にタップする必要があります(どちらも相互に排他的なイベントは、ところで)。
アップデート2:
CodeBehindのDescriptionLayerOpacity
ステートメントを削除した後、すべてがうまく機能しているようです。しかし、それを仕事にするためにモデル内の不透明性プロパティへのバインディングはまだ臭いのある解決策です。
ここでの解決策を見てください。
これが正確に問題であるかどうかわからないが、UserControl
によって吸収されるので、ListView
が保留イベントを受信していないように聞こえます。
上記の解決策では、DataTemplates
にGrid
ListViewItem
をラップし、ホールドイベントをそれに接続する必要があります。多分これは役に立ちますか?