Oleg Vazhnev
Oleg Vazhnev

Reputation: 24067

Databinding + DataGrid - how to connect?

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...

Upvotes: 0

Views: 219

Answers (5)

Vinit Sankhe
Vinit Sankhe

Reputation: 19895

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.

Upvotes: 0

blindmeis
blindmeis

Reputation: 22445

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

Upvotes: 0

Ed Bayiates
Ed Bayiates

Reputation: 11230

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);
}

Upvotes: 1

Stephen Booher
Stephen Booher

Reputation: 6542

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.

Upvotes: 1

Tigran
Tigran

Reputation: 62265

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.

Upvotes: 0

Related Questions