UWP ListView 拖放后更新行背景

UWP ListView Update Row Background After Drag and Drop

我目前这样做是为了使我的 ListView 具有交替行背景。

    private void SongsListView_ContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
    {
        if (AlternatingRowColor)
            args.ItemContainer.Background = args.ItemIndex % 2 == 0 ? Helper.WhiteSmokeBrush : Helper.WhiteBrush;
    }

此外,我还允许 ListView 能够拖放项目。但是,即使我这样做,行颜色在删除后也不会更新其颜色:

    private void SongsListView_DragItemsCompleted(ListViewBase sender, DragItemsCompletedEventArgs args)
    {
        sender.UpdateLayout(); // Refresh Row Color
    }

意味着我的 ListView 在拖放后没有交替背景。

我应该如何更新它的背景?

ContainerContentChanging为初始化渲染,UpdateLayout用于保证元素已经渲染完成,而不是重新渲染整个列表。

对于您的情况,我建议使用IValueConverter 进行背景颜色转换。您可以向数据类型添加 Index 属性 以标识它现在的位置。

这是一个简单的例子:

TestModel.cs

public class TestIndex:INotifyPropertyChanged
{
    private int _index;
    public int Index
    {
        get => _index;
        set
        {
            _index = value;
            OnPropertyChanged();
        }
    }

    // other properties

    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName]string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

converter.cs

public class BackgroundConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        if(value is int index)
        {
            // You can change color here.
            if (index % 2 == 0)
                return new SolidColorBrush(Colors.Red);
            else
                return new SolidColorBrush(Colors.Blue);
        }
        return new SolidColorBrush(Colors.Red);
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

xaml

<Page ...>
    <Page.Resources>
        <local:BackgroundConverter x:Key="BackgroundConverter"/>
        <DataTemplate x:Key="DefaultRow" x:DataType="local:TestIndex">
            <Grid Background="{x:Bind Index,Converter={StaticResource BackgroundConverter}, Mode=OneWay}" Height="50">
            </Grid>
        </DataTemplate>
    </Page.Resources>

    <Grid>
        <ListView ItemsSource="{x:Bind TestCollection}"
                  IsItemClickEnabled="True"
                  AllowDrop="True"
                  CanReorderItems="True"
                  IsSwipeEnabled="True"
                  ItemTemplate="{StaticResource DefaultRow}"
                  >
            <ListView.ItemContainerStyle>
                <Style TargetType="ListViewItem">
                    <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
                    <Setter Property="VerticalContentAlignment" Value="Stretch"/>
                </Style>
            </ListView.ItemContainerStyle>
        </ListView>
    </Grid>
</Page>

xaml.cs

private ObservableCollection<TestIndex> TestCollection = new ObservableCollection<TestIndex>();
public ListViewPage()
{
    this.InitializeComponent();
    for (int i = 0; i < 10; i++)
    {
        TestCollection.Add(new TestIndex()
        {
            Index = i
        });
    }
    TestCollection.CollectionChanged += CollectionChanged;
}

private void CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    for (int i = 0; i < TestCollection.Count; i++)
    {
        TestCollection[i].Index = i;
    }
}

这是因为在 ListView 中拖放项目时不会触发 DragItemsCompleted 事件。因为本质上是集合元素的删除和添加,所以需要为集合注册CollectionChanged事件

此致。

一个更简单的解决方案是:

    private void SongsListView_DragItemsCompleted(ListViewBase sender, DragItemsCompletedEventArgs args)
    {
        for(int i = 0; i < sender.Items.Count; i++)
        {
            var container = sender.ContainerFromIndex(i) as ListViewItem;
            container.Background = i % 2 == 0 ? Helper.WhiteSmokeBrush : Helper.WhiteBrush;
        }
    }