0

This question is the result of my previous question DataGrid - grid selection is reset when new Data is arrived

=====================================================================

I have such DataGrid

<DataGrid AutoGenerateColumns="True" HorizontalAlignment="Stretch" Name="dataGrid1" VerticalAlignment="Stretch" ItemsSource="{Binding DataList}" IsReadOnly="True"/>

In my ViewModel I have such field:

public ObservableCollection<ConsoleData> DataList { get; set; }

And such method which is called every second:

private void model_DataArrived(List<ConsoleData> dataList)
{
    DataList.Clear();
    dataList.ForEach(x => DataList.Add(x));
}

=====================================================================

We have figured out that because I call DataList.Clear the selection in the UI control is cleared as well and I don't want this to happen. So likely I should not replace instances of ConsoleData in ViewModel, instead of that I should update these instances.

But ObservableCollection observes for add/remove I guess and doesn't observe for update isn't? So if I will update instances DataBinding will not work?

Another problem with the current application is that dataList.ForEach(x => DataList.Add(x)); forces databinding to execute on each iteration instead of executing only at the end?

Overall what is the right way to do what I want to do because current application doesn't work and has too many problems...

Community
  • 1
  • 1
Oleg Vazhnev
  • 23,239
  • 54
  • 171
  • 305

5 Answers5

1

It's not clear how you are planning on updating an item in your ObservableCollection. There are at least two ways to do this. One way is to update all the properties that are changed in a ConsoleData object. In this case, you would have ConsoleData implement INotifyPropertyChanged. Another way is a direct update of item in the ObservableCollection. To do this, you could use the SetItem method of the ObservableCollection. This will raise the CollectionChanged event as the MSDN documentation for SetItem indicates.

Since you have indicated that you are using MVVM, the generally accepted thing to do would be to make your ObservableCollection be a collection of ConsoleDataViewModel instead of ConsoleData.

Another problem with the current application is that dataList.ForEach(x => DataList.Add(x)); forces databinding to execute on each iteration instead of executing only at the end?

I don't think you will have the refresh problem if you modify your model_DataArrived method to update instead of clear/add as indicated above.

Stephen Booher
  • 6,522
  • 4
  • 34
  • 50
  • hmm... i would like to follow MVVM so I probably should use `ConsoleDataViewModel` instead of `ConsoleData`? Where can I read more about that? Jason Dolinger extends `Dependency Object` and implements some `Dependency Properties` should I do the same? It looks very complicated – Oleg Vazhnev Nov 23 '11 at 09:09
  • 1
    That video is one good way, and [Josh Smith's MSDN article](http://msdn.microsoft.com/en-us/magazine/dd419663.aspx) is another good resource for MVVM. You can use either DependencyObject or INotifyPropertyChanged, and you might notice that Josh Smith didn't use DependencyObject at all when he implemented his view models in the article. That is also the approach that I happen to be using in my own project. Either approach is valid though, and if you did decide to use dependency properties, then yes, you would have to do what you described in your comment. – Stephen Booher Nov 23 '11 at 14:26
1

The problem is the ObservableCollection not notifying when an item is changed; it notifies only when items are added and removed, as you say. To solve this problem I created a class I call VeryObservableCollection. For each object added, it hooks the object's NotifyPropertyChanged event to a handler that triggers a CollectionChanged event. For each object removed, it removes the handler. Very simple and should solve your issue. You just need to make sure you implement NotifyPropertyChanged on the objects held in the collection. For example:

public class VeryObservableCollection<T> : ObservableCollection<T>

/// <summary>
/// Override for setting item
/// </summary>
/// <param name="index">Index</param>
/// <param name="item">Item</param>
protected override void SetItem(int index, T item)
{
    try
    {
        INotifyPropertyChanged propOld = Items[index] as INotifyPropertyChanged;
        if (propOld != null)
            propOld.PropertyChanged -= new PropertyChangedEventHandler(Affecting_PropertyChanged);
    }
    catch (Exception ex)
    {
        Exception ex2 = ex.InnerException;
    }
    INotifyPropertyChanged propNew = item as INotifyPropertyChanged;
    if (propNew != null)
        propNew.PropertyChanged += new PropertyChangedEventHandler(Affecting_PropertyChanged);

    base.SetItem(index, item);
}
Ed Bayiates
  • 11,060
  • 4
  • 43
  • 62
0

I think you can do something like this

private ObservableCollection<ConsoleData> dataList;
public ObservableCollection<ConsoleData> DataList 
{ 
   get {return dataList; } 
   set {dataList = value;} 
}

And your data manipulations access only the field dataList. One time fiished manipulation force DataBinding to update, or reassign it, forcing in this way Biding to raise notification to WPF.

Should work.

Tigran
  • 61,654
  • 8
  • 86
  • 123
  • but this should resolve the problem of continuose refresh of UI, which is the problem of this question as much as I understood. – Tigran Nov 22 '11 at 22:04
  • no the question is how to do thing to 1. solve refresh UI problem. 2. solve "selection lost" problem. 3. solve "perfomance" issue if exist. :) – Oleg Vazhnev Nov 23 '11 at 09:00
0

if your ConsoleData implements INotifyPropertyChanged you can simply update these and you will see the changes in your ui - without selection lost.

blindmeis
  • 22,175
  • 7
  • 55
  • 74
0

OK first we need to understand that an item which was the source of selection on any Selector controls such as ListBox, DataGrid etc., if removed, will loose the selection.

For this please use a bulk adding and single notifying FastObservableCollection.

But to mainain such selection, you will have to set the selected item / value back to the DataGrid once Clear and AddRange takes place.

Community
  • 1
  • 1
WPF-it
  • 19,625
  • 8
  • 55
  • 71