views:

1160

answers:

3

I'm passing IEnumerable Collection into WPF DataGrid through DataGrid.ItemSource property. But it doesn't update DataGrid when I'm trying to change collection items in a code. Why?

+3  A: 

You need a to bind to a type that implements the INotifyCollectionChanged interface so it supplies events the databinding can use to monitor when items are added or removed. The best type for this in WPF is ObservableCollection<>, which has a constructor that will accept your IEnumerable:

ObservableCollection<string> collection = new ObservableCollection<string>(iEnumerableobject);
dataGrid.ItemSource = collection;
collection.Add("Wibble");

Will update properly.


From your comments to the other answer it looks like you need to invoke the add call from inside the UI thread. Without knowing your code in more details I don't know why you need to do this, but let's assume that you are getting the data from a service in the background:

private ObservableCollection<string> collection;

public void SetupBindings()
{
    collection = new ObservableCollection<string>(iEnumerableobject);
    dataGrid.ItemSource = collection;
    //off the top of my head, so I may have this line wrong
    ThreadPool.Queue(new ThreadWorkerItem(GetDataFromService));
}

public void GetDataFromService(object o)
{
     string newValue = _service.GetData();

     //if you try a call add here you will throw an exception
     //because you are not in the same thread that created the control
     //collection.Add(newValue);

     //instead you need to invoke on the Ui dispatcher
     if(Dispather.CurrentDispatcher.Thread != Thread.CurrentThread)
     { 
         Dispatcher.CurrentDispatcher.Invoke(() => AddValue(newValue));
     } 
}

public void AddValue(string value)
{
    //because this method was called through the dispatcher we can now add the item
    collection.Add(value);
}

As I say, I don't have an IDE to hand, so this probably won't compile, but will point you in the right direction.

Depending on what exact task you are doing in the background though, there may be better ways to do this. My example above would be much easier to implement using a backgroundworker, so you may want to read up on that too.

Martin Harris
+1 for that man, and not just for using "Wibble" in an answer. Well done I say! . . . and yes, I am feeling slightly strange this afternoon . . .
Binary Worrier
I changed to ObservableCollection, but it still doesn't make difference. It's shows proper data when I first start a program, but never updates Grid after then... I'm doing something wrong
Ike
+1  A: 

You need to use an ObservableCollection instead. (Or make your own class the wraps the collection and implement the INotifyPropertyChanged interface)

Simon P Stevens
When I'm trying to make changes in collection, VS says:This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.
Ike
When a collection is bound to the GUI, you can only make changes to the collection from the main GUI thread. You can do this by calling Invoke on the forms dispatcher. Do if(Dispather.CurrentDispatcher.Thread != Thread.CurrentThread){ and then call Dispatcher.CurrentDispatcher.Invoke(and pass in a delegate to your method) See here: http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.invoke.aspx
Simon P Stevens
You need to make all of your updates on the UI thread, since WPF only supports modifying controls from the thread that they were created on.
Andy
A: 

You also can use a collection that implements INotifyCollectionChanged Interface if you can't use ObservableCollection for some reason...

Ike