我有一个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。
这个问题与虚拟化有关吗?我该如何解决这个问题?
替代方案可以。
更新:
一些SO帖子表明回收模式导致物品被重复使用。我添加了
VirtualizingStackPanel.VirtualizationMode="Standard"
到我的ListView,但问题出乎意料地持续存在。
所以现在我需要想办法防止其他项重复相同的不透明度值(这不是数据绑定,因为它是通过故事板设置的)。
更新2 :
现在,当显示项目退出视图时,保持显示项目完全消失的描述:
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
答案 0 :(得分:2)
我找到了解决方法;我在我的模型中添加了一个名为DescriptionLayerOpacity
的属性,并在我的视图模型中向我的0
添加新项目时将其设置为默认值ObservableCollection
我还添加了双向绑定来更改源属性(DescriptionLayerOpacity
),以便使用故事板所做的更改来更新视图:
<Grid ... Opacity="{Binding DescriptionLayerOpacity, Mode=TwoWay}">
<TextBlock .../>
</Grid>
简而言之,所有UserControl的数据都必须是数据绑定,以避免在ListView中的其他项中重复。
这不是一个优雅的解决方案,它还没有经过全面测试。在找到真正的解决方案之前,这就足够了。
更新:未完全正常工作
我最近发现,当选择其他项目时,有些项目不响应。为了让这些项目得到回应,我必须在点击+保持事件之前点击(顺便说一下,两者都是互斥事件)。
更新2:
在删除代码隐藏中的if
语句后,一切似乎都正常工作。但是绑定到模型中的不透明属性以使其工作仍然是一个有臭味的解决方案。
答案 1 :(得分:1)
我喜欢你在这里尝试的方式。对于触摸屏设备,我们没有MouseOver
事件,因此这是您想要显示一些额外信息而不会弄乱UI的方法之一。
然而,一个更清晰的解决方案是创建一个可重用的Behavior
,它封装了所有UI逻辑&amp;动画。
为此,您首先需要包含参考Behaviors SDK (XAML)
。
Behavior
实施是直截了当的。 AssociatedObject
将是接收触摸事件的Grid
,然后您需要创建DependencyProperty
TextBlockName
来检索描述TextBlock
实例。有了实例后,你只需要在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;
}
}
然后,Behavior
可以附加到DataTemplate
的顶级Grid
。请注意,您不再需要UserControl
来包装它。
此外,请确保您拥有Grid
的背景色,以便它可以接收触摸事件。我做的最后一件事是将ListView
的{{1}}的{{1}}更改为ItemContainerStyle
,以便HorizontalContentAlignment
一直延伸到右边
Stretch
答案 2 :(得分:0)
我不确定这是不是你的问题,但听起来UserControl
没有接收到hold事件,因为它被ListView
吸收了?
上面的解决方案描述了需要将DataTemplates
Grid
包装在ListViewItem
中,并将Hold事件附加到该{{1}}。也许这会有所帮助吗?