Reputation: 24067
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
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
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
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
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
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