不使用INPC强制DataGrid行刷新

时间:2014-10-06 23:39:04

标签: wpf datagrid

我有一个数据网格绑定到一组没有实现INotifyPropertyChanged的项目(我不能改变)。一旦我更改了特定项目中的属性,如何强制刷新相应行中的所有绑定?

我不想使用ObservableCollection<T>并将原始项目替换为相同类型但具有新数据的新项目,因为那样我将丢失当前选择。我可以使用新的替换项设置SelectedItem,但是当我替换项目时,我会触发SelectionChanged事件。

3 个答案:

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