tags:

views:

316

answers:

2

Hi,

Firstly I know that there are many question and solutions to correct thread marshalling from threads other than background threads. All the questions and solutions I have found have focused on scenarios where the list or business object itself raises an event that the Windows form can subscribe to and then correctly marshall the update to the main UI thread.

In my case the list of business objects is being updated by a background thread in a seperate layer . I want this list bound to a control on the main thread. Do I really need to expose an event to the UI from the business object list so that the update can be marshalled correctly?. Can I not quietly update the business object list and have these updates propagated to the UI , without somehow having to expose a list changed event to the UI?

EDIT :

My problem is essentially this :The INotifyProperty changed is fired after a property has been changed. A control bound to an object implementing this interface will attempt to update, if the thread causing the event to fire is not the UI thread, we have a problem. So we need to notify the UI thread that we want to update so that update can be handled in a thread safe manner , this means that the background thread updating objects can not simply go about its business, it has to ask permission to update the objects or ask the UI to make the changes to the object on its behalf. This is what I mean by the UI being pulled into handle object updates.

+1  A: 

I've posted an option here (including example) on this old usenet post - look for ThreadedBindingList (don't panic - most of the code is setting up the example; the list class is very small); it might help a bit, but IMO you might do better to simply do the UI updates a bit later...

(don't miss the updates lower in the thread)

Marc Gravell
That ThreadedBindingList looks really nice. I think I will take it on a little test drive.
Fredrik Mörk
Thanks Marc I will take a look.
Mule
Marc are you suggesting that I allow the UI to handle the updates?Please see my comment to Yoopergeek below.
Mule
I'm saying it is a possible option. YMMV. It does, however, complicate things doing this type of cross-thread work...
Marc Gravell
Marc, i just tested your threadedbinding list , works great , some error handling and I think I can use it. Thanks.
Mule
A: 

My experience has been that if you have business objects bound to the UI, any changes made to those objects must implicitly be performed on the UI thread, or you will get a cross-thread exception.

Changing objects from a non-UI thread, when those objects are databound to the UI, is bad news.

See, if you're objects implement binding-friendly patterns (like INotifyPropertyChanged for example,) and you bind one/many of those objects to the UI, and you behind-the-scenes update your object in a manner that causes any of those binding-friendly events to burple up to the UI, your 'object has changed' notification is making it's way to UI code, causing a cross-thread exception.

Update: One way to get around your objects raising the offending events would be to implement some sort of 'STFU' object-level variable that could be set to true when updates are being made to object state from a non-UI thread. Then, in your "OnRaiseMyEvent(...)" method(s) you can check the status of the STFU variable - if true, STFU, otherwise, raise the event.

Update #2: Ah, with the update to the question, here's what I've done in this situation: Pass an ISynchronizeInvoke to your business object's constructor. Then, the business object can handler whether it needs to marshal an event-raise to the UI thread:

public class MyObject { 
   private ISynchronizeInvoke _Invoker;

   public MyObject(ISynchronizeInvoke invoker) { 
      _Invoker = invoker;
   }

   private void OnPropertyChanged(string propertyName) {
      PropertyChangedEventHandler handlers = this.PropertyChanged;
      if (handlers != null) { 
      if (_Invoker.InvokeRequired) { 
        _Invoker.Invoke(handlers, new PropertyChangedEventArgs(propertyName)); 
      } else { 
         handlers(new PropertyChangedEventArgs(propertyName);
      }
   }
}
Yoopergeek
I know that is exactly the problem! I am implementing those binding friendly interfaces. But if I have the UI handle the updates that I am making to the business objects , I am breaking encapsulation. The UI is being pulled into handling updates that by all rights has no business knowing about.
Mule
@Mule: "The UI is being pulled into handling updates that by all rights has no business knowing about." : Um, but that's exactly why you implement the binding interfaces in the first place. . . it *is* the UI's business to listen to those events.
Yoopergeek
@Yoopergeek , please see the edit to the original post
Mule