我有一个数据网格绑定到一组没有实现INotifyPropertyChanged
的项目(我不能改变)。一旦我更改了特定项目中的属性,如何强制刷新相应行中的所有绑定?
我不想使用ObservableCollection<T>
并将原始项目替换为相同类型但具有新数据的新项目,因为那样我将丢失当前选择。我可以使用新的替换项设置SelectedItem
,但是当我替换项目时,我会触发SelectionChanged
事件。
答案 0 :(得分:3)
我想到的第一个答案是将您的集合包装到ICollectionViewSource中,并在收到项目更新时调用Refresh():
public partial class MainWindow : Window
{
public ICollectionView MyCollectionView { get; set; }
private List<NotNotifiableObject> internalList;
private Random _rnd;
public MainWindow()
{
InitializeComponent();
DataContext = this;
internalList = new List<NotNotifiableObject>();
MyCollectionView = CollectionViewSource.GetDefaultView(internalList);
_rnd = new Random(DateTime.Now.Second);
for (int i = 0; i < 31; i++)
{
internalList.Add(new NotNotifiableObject { Age = i, Name = "John Doe " + i });
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var index = _rnd.Next(0, 31);
var objectToUpdate = internalList[index];
objectToUpdate.Name = objectToUpdate.Name + " | " + DateTime.Now;
MyCollectionView.Refresh();
}
}
internal class NotNotifiableObject
{
public string Name { get; set; }
public int Age { get; set; }
}
您只需将datagrid绑定到此ICollectionView属性
即可 <DataGrid ItemsSource="{Binding MyCollectionView}" ></DataGrid>
这很好但如果您的列表中有很多经常更新的项目会影响性能
答案 1 :(得分:1)
您可以在更新项目后使用DataGrid中的Items.Refresh()方法,它不会引发SelectionChanged事件。
public partial class MainWindow : Window
{
public ObservableCollection<Item> Items { get; set; }
public MainWindow()
{
InitializeComponent();
Items = new ObservableCollection<Item>();
for (int i = 1; i <= 100000; i++)
{
Items.Add(new Item() { Name = "Item" + i.ToString(), Value = i });
}
DataContext = this;
}
private void buttonUpdate_Click(object sender, RoutedEventArgs e)
{
var item = Items[1];
item.Name = "Item2 updated";
item.Value = 22;
dataGrid.Items.Refresh();
}
private void dataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
System.Diagnostics.Debug.Print("dataGrid_SelectionChanged");
}
}
public class Item
{
public string Name { get; set; }
public double Value { get; set; }
}
XAML
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<DataGrid x:Name="dataGrid"
ItemsSource="{Binding Items}"
Grid.Row="0"
SelectionChanged="dataGrid_SelectionChanged"/>
<Button x:Name="buttonUpdate"
Content="Update"
Width="100"
Grid.Row="1"
Click="buttonUpdate_Click"/>
</Grid>
</Window>
答案 2 :(得分:1)
你不能改变观点:对象的对象而不是集合。
你不能创建一个INPC对象来包装你的无INPC对象的属性吗?然后,当您收到更新的对象时,您更新INPC对象(我称之为适配器)?您的收藏将包含这些适配器的列表。
实际上,为了获得更好的答案,有助于获得代码(特别是更新无INPC对象的部分)。
但请记住,一般情况下,最好使用Adapters(或装饰器,无论其名称如何)将数据呈现给您的视图。
第一个原因是您始终具有原始业务对象无法容纳的特定表示需求(聚合属性,翻译值等)。
因此,使用适配器至少提供以下两种解决方案:1)将非INPC对象转换为可通知的对象; 2)提供更灵活,面向表示的对象,该对象能够根据视图的需要呈现数据。 / p>