如何在重用之前清理 ListViewItem 的状态?
Posted
技术标签:
【中文标题】如何在重用之前清理 ListViewItem 的状态?【英文标题】:How to Cleanup the ListViewItem's state before they get reused? 【发布时间】:2021-11-22 12:19:14 【问题描述】:问题是listview使用了虚拟化,当item改变外观时,list刷新后仍然存在。这是微软工程师的回答
这是由 ListView 的默认面板的虚拟化特性引起的 (项目堆栈面板)。它本质上重用了相同的 ListViewItem (容器),当它重用它们时,它可能处于 不正确。当您使用堆栈面板时,没有虚拟化和 每个项目都有一个容器(不可重复使用),您可以想象 如果您的列表中有很多项目,则会非常耗时。你可以 尝试使用 PrepareContainerForItemOverride, ClearContainerForItemOverride 清理 ListViewItem 的状态 在它们被重用之前。更好的是使用 ContainerContentChanging 事件并在那里执行,因此您不需要 派生类型。
很遗憾,我找不到使用 PrepareContainerForItemOverride、ClearContainerForItemOverride 和 ContainerContentChanging 方法的示例。
如何清除 ContainerContentChanging 中 ListViewItem 的状态?
更新:
用户控制:
<Grid>
<SwipeControl x:Name="ListViewSwipeContainer">
<Grid VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<TextBlock
Margin="10,5,200,5"
HorizontalAlignment="Left"
VerticalAlignment="Center"
FontSize="18"
Text="Binding ElementName=subsceneView, Path=Title"
TextWrapping="Wrap"/>
<AppBarButton
Name="OpenFolderButton"
Grid.RowSpan="2"
MinWidth="75"
Margin="10,0,10,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Click="OpenFolderButton_Click"
Icon="OpenLocal"
IsTabStop="False"
Label="Open Folder"
Visibility="Collapsed"/>
<AppBarButton
Name="DownloadHoverButton"
Grid.RowSpan="2"
Margin="10,0,10,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Click="DownloadHoverButton_Click"
Icon="Download"
IsTabStop="False"
Label="Download"
Visibility="Collapsed"/>
</Grid>
</SwipeControl>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="HoveringStates">
<VisualState x:Name="HoverButtonsHidden"/>
<VisualState x:Name="HoverButtonsShown">
<VisualState.Setters>
<Setter Target="DownloadHoverButton.Visibility" Value="Visible"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
后面的代码:
public sealed partial class SubsceneUserControl : UserControl
#region DependencyProperty
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(SubsceneUserControl),
new PropertyMetadata(string.Empty));
public string Title
get return (string)GetValue(TitleProperty);
set SetValue(TitleProperty, value);
#endregion
public SubsceneUserControl()
this.InitializeComponent();
private void UserControl_PointerEntered(object sender, PointerRoutedEventArgs e)
if (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Mouse ||
e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Pen)
VisualStateManager.GoToState(sender as Control, "HoverButtonsShown", true);
private void UserControl_PointerExited(object sender, PointerRoutedEventArgs e)
VisualStateManager.GoToState(sender as Control, "HoverButtonsHidden", true);
private void OpenFolderButton_Click(object sender, RoutedEventArgs e)
private void DownloadHoverButton_Click(object sender, RoutedEventArgs e)
OpenFolderButton.Visibility = Visibility.Visible;
DownloadHoverButton.Visibility = Visibility.Collapsed;
这是我的列表视图
<ListView
x:Name="listv"
ItemsSource="x:Bind Subtitles, Mode=OneWay">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:SubsceneDownloadModel">
<local:SubsceneUserControl Title="x:Bind Title"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
private void AddItems()
Subtitles?.Clear();
for (int i = 0; i < 10; i++)
Subtitles.Add(new SubsceneDownloadModel Title = "Test " + i );
【问题讨论】:
为什么不为类实现 INotifyPropertyChanged 以禁用错误重用行为? @NicoZhu-MSFT 我不知道怎么做? 【参考方案1】:ListViewItem 在被重用之前的状态
对于这种情况,更好的方法是使用 mvvm 绑定并为模型类实现INotifyPropertyChanged
。更多详情请参考Data binding in depth。
例如
模型类
public class Model : INotifyPropertyChanged
public Model(string name)
this.Name = name;
private string _name;
public string Name
get
return _name;
set
_name = value;
NotifyPropertyChanged();
private bool _visible;
public bool Visible
get => _visible;
set
_visible = value;
NotifyPropertyChanged();
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
if (PropertyChanged != null)
// PropertyChanged is always null.
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
Xaml
<ListView x:Name="MyList">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Binding Name" />
<SymbolIcon
x:Name="MySbl"
HorizontalAlignment="Right"
Symbol="Accept"
Visibility="Binding Visible" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
用法
MyList.ItemsSource = new ObservableCollection<Model>
new Model("hello"),
new Model("hello1"),
new Model("hello2"),
new Model("hello3"),
new Model("hello4"),
new Model("hello5"),
new Model("hello6"),
;
【讨论】:
谢谢,但是我的应用如下 在列表视图中点击按钮后会执行操作,如果成功,按钮必须隐藏。由于不容易访问数据模板的组件或以后更改数据集合,所以我在 usercontrol 中定义了数据模板在您的方法中,如何更新所需的记录并在操作后隐藏或显示按钮?为了更好地了解程序的状态,我会更新第一个帖子请看它 建议你绑定按钮的Visibility view bool值,如果你想隐藏这个按钮,请调用按钮命令方法并将当前项的bool值设置为false。这是类似的案例reply你可以参考以上是关于如何在重用之前清理 ListViewItem 的状态?的主要内容,如果未能解决你的问题,请参考以下文章
如何设置 Listviewitem 边距以使用 Listviewitem 的背景颜色?