【发布时间】:2019-09-24 04:23:39
【问题描述】:
什么
DataGrid 绑定到 ViewModel 中的 ObservableCollection。
每 2 秒,交替修改/添加一个项目。
修改/添加的项目数据网格行突出显示 1 秒。
问题
添加的项目必须插入到给定的索引处,不一定在 ObservableCollection 的末尾。这是通过使用Insert(int index, ListItemVM item) 来实现的。
错误
该项目被添加到索引 1 的第二个位置。 UI 会相应更新并突出显示新项目但也错误地突出显示最后一个项目。我真的很想摆脱不需要的行为,但我不知道如何。
代码可运行:
XAML
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<DataGrid ItemsSource="{Binding MyList}" AutoGenerateColumns="False" CanUserAddRows="False" GridLinesVisibility="None" HeadersVisibility="None" BorderThickness="0" ScrollViewer.VerticalScrollBarVisibility="Visible">
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="Background" Value="Green" />
<Style.Triggers>
<EventTrigger RoutedEvent="Binding.TargetUpdated">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="00:00:01" Storyboard.TargetProperty="Background.Color" From="Blue" To="Transparent" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Label>
<TextBlock Text="{Binding Id}" />
</Label>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Label>
<TextBlock x:Name="txtTheData" Text="{Binding TheData, NotifyOnTargetUpdated=True}" Background="Transparent" />
</Label>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Window>
代码隐藏
using System.Windows;
using WpfApp1.ViewModels;
namespace WpfApp1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
DataContext = new MainWindowVM();
InitializeComponent();
}
}
}
视图模型
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows.Threading;
namespace WpfApp1.ViewModels
{
public class MainWindowVM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
Random random = new Random();
public ObservableCollection<ListItemVM> MyList { get; set; } = new ObservableCollection<ListItemVM>
{
new ListItemVM(1, "Data1"),
new ListItemVM(2, "Data2"),
new ListItemVM(3, "Data3"),
};
bool mustAdd;
public MainWindowVM()
{
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(2000);
timer.Tick += (object sender, EventArgs e) =>
{
mustAdd = !mustAdd;
if (mustAdd == false)
{
// Emulate Update existing
var nextData = new string(Enumerable.Repeat("ABCDEFG", 10).Select(s => s[random.Next(s.Length)]).ToArray());
MyList[1].SetNewData(nextData);
}
else
{
// Emulate Add new
var newItem = new ListItemVM(99, "old");
MyList.Insert(1, newItem);
// Notify the UI of the change
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(MyList)));
newItem.SetNewData("NEW");
}
};
timer.Start();
}
}
}
项目视图模型
using System.ComponentModel;
namespace WpfApp1.ViewModels
{
public class ListItemVM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public int Id { get; set; }
public string TheData { get; set; }
public ListItemVM(int id, string theData)
{
Id = id;
TheData = theData;
}
internal void SetNewData(string nextData)
{
// Change data
TheData = nextData;
// Notify the UI of the change
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(TheData)));
}
}
}
【问题讨论】:
-
只禁用项目容器回收(虚拟化)。
-
你并不总是插入你也在更新现有的项目。 c# 中的集合使用零基索引。因此第一个是索引 0,第二个是 1。一个 observablecollection 实现了 inotifycollectionchanged。如果您将集合中的一个项目设置为另一个对象甚至它本身,它会引发整个项目的更改。如果插入。它为该新项目提出。您可以在视图中处理该事件并使用它来启动动画。
-
@andy 更新工作正常,在示例中是为了完成。该错误是关于添加项目
-
@ibiza:那你为什么要处理
Binding.TargetUpdated,而不是像我建议的here 那样使用附加行为?最后一行也将引发此事件。
标签: c# .net wpf xaml eventtrigger