Skip to main content

Microsoft Silverlight

Answered Question DataGrid binding issueRSS Feed

(0)

Roman.Ivanashko
Roman.Iv...

Member

Member

0 points

6 Posts

DataGrid binding issue

I have a datagrid where I show some items. They are in an ObservableCollection, each item is INotifyPropertyChanged. Binding is described in xaml.

Issue that in some cases I have to update bound items in another thread. It's done to have an ability to update business objects using sync calls to web service.

But I get cross-thread exception updating properties of an object even if I rebind my datagrid to empty collection or clear ItemsSource property value. Looks like changing ItemsSource don't clear out old bindings and the weak references that are used there still valid and there are subscribers to PropertyChanged.

So the question is how I can actually unbound an object? It means get PropertyChanged event cleared out from the subscribes which are not bound to the object anymore? I believe there are some workarounds but is there any "correct" way?

 

Sledge70
Sledge70

Contributor

Contributor

5932 points

1,047 Posts

Re: DataGrid binding issue

Can't you just set the observablecollection to a new instance, populate it then bind it to your datacontext.

We do this without any cross thread exceptions.

______________________________________________________
Please mark replies as answers if they answered your question...

Flexman on Silverlight

Roman.Ivanashko
Roman.Iv...

Member

Member

0 points

6 Posts

Re: Re: DataGrid binding issue

I can but it actually doesn't help. I need the object that was bound to the grid in some other place and when I try to update that object in not UI thread I get cross reference becuase binding is kind of alive inspire of the fact that my grid is bound to a new collection.

Sledge70
Sledge70

Contributor

Contributor

5932 points

1,047 Posts

Re: Re: Re: DataGrid binding issue

How are you unbinding it?

Does anything in the collection have a ref to a UI Element?

______________________________________________________
Please mark replies as answers if they answered your question...

Flexman on Silverlight

Roman.Ivanashko
Roman.Iv...

Member

Member

0 points

6 Posts

Re: Re: Re: Re: DataGrid binding issue

I tried different ways:

Setting SourceItens to null, to empty collection. Then

grd.SetValue(DataGrid.ItemsSourceProperty, null);

also ClearValue(DataGrid.ItemsSourceProperty)

Does't help. When I debug I can see in the PropertyChanged invocation list the ui subscriber.

Object knows nothing about the UI.

Sledge70
Sledge70

Contributor

Contributor

5932 points

1,047 Posts

Re: Re: Re: Re: DataGrid binding issue

There is an issue where you remove controls from the visualtree but the name is left hanging around so you can't re-insert a new control with the same name.

Wonder if it has something to do with that scenario.

As a workaround can you copy everything out of the collection or is it too large?

______________________________________________________
Please mark replies as answers if they answered your question...

Flexman on Silverlight

yifung
yifung

Contributor

Contributor

3315 points

541 Posts

Microsoft
Answered Question

Re: DataGrid binding issue

Updating your business object in a background thread is fine, but when that object raises a PropertyChanged event due to the update, that event should be raised on the UI thread.  You can go into your objects implementation of INotifyPropertyChanged, and when you're rasing the event, first check if you're on the UI thread, if not, use BeginInvoke to raise the event.

Yifung Lin [MSFT]

Sledge70
Sledge70

Contributor

Contributor

5932 points

1,047 Posts

Re: DataGrid binding issue

yifung:

Updating your business object in a background thread is fine, but when that object raises a PropertyChanged event due to the update, that event should be raised on the UI thread.  You can go into your objects implementation of INotifyPropertyChanged, and when you're rasing the event, first check if you're on the UI thread, if not, use BeginInvoke to raise the event.

The problem here is for high volume data updates you don't want to be hitting the UI with every update. You want to batch them into a collection then bind it. Normally you would provide new instances of the entity and replace the entity in the observable collection every say 200ms.

The issue Roman is facing is that he wants to unbind the observable collection from the UI and be able to do some processing on it in a background thread. There seems to be a bug with SL not releasing the OC (ObservableCollection).

Is the OC being initially created on the UI thread? Have you tried creating the OC on the background thread initially?

______________________________________________________
Please mark replies as answers if they answered your question...

Flexman on Silverlight

yifung
yifung

Contributor

Contributor

3315 points

541 Posts

Microsoft

Re: DataGrid binding issue

If you set the DataGrid's ItemsSource to null, and then update the items, you shouldn't see any cross thread exceptions.  Is that what you're seeing?

If you want to keep the items bound to the DataGrid while you're updating them in a background thread, you'd have to not raise any PropertyChanged notifications for the items until you're done updating.  This could get messy since you could blow away and changes the user made in the UI

Yifung Lin [MSFT]

Paul Cavacas
Paul Cav...

Member

Member

42 points

27 Posts

Re: DataGrid binding issue

What about either not raising PropertyChanged events in your Set of your property or if you need to have this for other things.  Then add a property that can be set to Suspend the PropertyChanged events, so when you are doing the background updates you first Suspend the PropertyChanged events, make all of your changes (none of which will fire the PropertyChanged event, since you have suspended them).  Then when you are done with the background updates you Unsuspend the PropertyChanged events, in the unsuspending you raise the PropertyChanged events for each of the properties that can be changed from the background thread.

This way you do not need to unbind the collection, it just enters into a state where it is not notifing the UI of changes.  Then when you are done with the background changes you leave this state and fire off all of the changed events (in the UI thread), so the UI is then updated.

Roman.Ivanashko
Roman.Iv...

Member

Member

0 points

6 Posts

Re: DataGrid binding issue

Thanks everyone for the answers. I believe I have to go with the BeginInvoke in the PropertyChanged. Suspending the event for each object in the collection (it actually a tree)  is overkill for me. 

Actually I'm doing something like this: 

       private void Button_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.Threading.Dispatcher dispatcher = Application.Current.RootVisual.Dispatcher;
            ThreadPool.QueueUserWorkItem(delegate
            {
                _coll = SuperDAL.GetDataFromService();
                SyncCallBroker.NotifyUI<ObservableCollection<ComplexNotifier>>(_coll, UpdateUI, dispatcher);
            });
        }

        private void UpdateUI(ObservableCollection<ComplexNotifier> methodCallResult)
        {
            grd.ItemsSource = methodCallResult;
        }

        private void DataGrid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            ComplexNotifier cn = ((ComplexNotifier)((DataGrid)sender).SelectedItem);
            _coll.Remove(cn);
            grd.SetValue(DataGrid.ItemsSourceProperty, null);
            grd.ItemsSource = new ObservableCollection<ComplexNotifier>();
            
            System.Windows.Threading.Dispatcher dispatcher = Application.Current.RootVisual.Dispatcher;
            ThreadPool.QueueUserWorkItem(delegate
            {
                cn.Update();
                SyncCallBroker.NotifyUI<ComplexNotifier>(cn, (ComplexNotifier c) => { _coll.Insert(0, c); }, dispatcher);
            });
        }  

Roman.Ivanashko
Roman.Iv...

Member

Member

0 points

6 Posts

Re: DataGrid binding issue

So I remove the object from collection and clear ItemsSource and when I do cn.Update(); it goes to web service and updates one of the cn properties and fires PropertyChanged event and I get cross reference exception.

Roman.Ivanashko
Roman.Iv...

Member

Member

0 points

6 Posts

Re: DataGrid binding issue

I impelmented the beginInvoke in the OnPropertyChanged realization and it did help. I even don't need to do anything with binding before updating objects in diff thread. So it sort of solves the problem but I'm still wondering why I could not undbind the collection...

Sledge70
Sledge70

Contributor

Contributor

5932 points

1,047 Posts

Re: Re: DataGrid binding issue

Probably because the PropertyChanged events are automatically wired up by SL for you. It looks like their is no intelligence to remove these events automatically when just removing a OC from a datacontext.

______________________________________________________
Please mark replies as answers if they answered your question...

Flexman on Silverlight
  • Unanswered Question
  • Answered Question
  • Announcement
Microsoft Communities