You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ListViewItem复用前清理其状态?ContainerContentChanging使用方法咨询

问题背景

ListView开启虚拟化特性后,列表项外观发生变更后刷新列表,变更后的状态会出现残留。
微软官方给出的原因说明:

该问题由ListView默认面板(ItemsStackPanel)的虚拟化特性导致,其会复用相同的ListViewItem(容器),复用的时候容器可能处于错误的旧状态。若使用普通StackPanel则不会开启虚拟化,每个列表项都会生成独立容器(无复用),但当列表项数量较多时该方案性能消耗会非常高。你可以尝试使用PrepareContainerForItemOverride、ClearContainerForItemOverride在ListViewItem复用前清理其状态,更推荐使用ContainerContentChanging事件实现该需求,无需自定义派生类。

需求

现需要通过ContainerContentChanging事件实现ListViewItem状态清理,暂无相关方法的使用示例参考。

现有代码参考

自定义UserControl XAML代码

<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>

自定义UserControl 后台代码

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;
    }

    // 新增重置状态的公共方法,方便外部调用
    public void ResetState()
    {
        VisualStateManager.GoToState(this, "HoverButtonsHidden", false);
        OpenFolderButton.Visibility = Visibility.Collapsed;
        DownloadHoverButton.Visibility = Visibility.Collapsed;
    }
}

ListView 相关代码

<ListView
    x:Name="listv"
    ItemsSource="{x:Bind Subtitles, Mode=OneWay}"
    ContainerContentChanging="listv_ContainerContentChanging">
    <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 });
    }
}

// 新增ContainerContentChanging事件处理
private void listv_ContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
{
    if (args.ItemContainer.ContentTemplateRoot is SubsceneUserControl userControl)
    {
        // 复用容器前先重置所有自定义状态
        userControl.ResetState();
    }
}
实现逻辑说明
  1. 首先在自定义UserControl中新增公共的ResetState方法,将控件的交互状态、按钮可见性全部重置为初始值
  2. 给ListView添加ContainerContentChanging事件,该事件会在容器复用、绑定新数据前触发
  3. 在事件处理逻辑中获取容器内的UserControl实例,调用重置方法即可清空旧状态,避免残留
  4. 该方案无需关闭虚拟化,也不需要自定义ListView派生类,性能损耗极低

内容的提问来源于stack exchange,提问作者user16474396

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 16:24:03