> Oh, and the Tablet PC's Ink API fires some events on background threads... > Go figure, eh?
Firing events from background threads for consumption in the UI is the hardest problem (for me) that I face at the moment. If I have a long running process that needs to invoke events that the UI has hooked then if I run this in a worker thread and trigger the events the event handlers will execute on the worker thread before continuing. This worker thread is not allowed to update the UI, so I have to invoke onto the UI thread in the event handler. After I invoke onto the UI thread I can't call into the model for the state that I need to render, because the worker thread may have locked the model which would cause the UI thread to block while waiting for its state. There are only two solutions that I can see. Have my business model throw immutable state objects with the event (i.e. EventArgs), or have the business model queue events and dispatch them on the UI thread when the worker thread has run to completion. For example, say I have a thread safe Person class like this (in pseudo code): public Person { public int Id { get; } public event NameChanged; public string Name { get; set; } public event PhoneChanged; public string Phone { get; set; } public void SyncWithDatastore( this.Name = GetNameFromWebService(this.Id); this.Phone = GetPhoneFromDatabase(this.Id); // etc. ) } If SyncWithDatastore() has to hit say a few disparate datasources, say one via a WebService and another in ActiveDirectory or a DB or something, then this could be a long running process, particularly if there is a problem that waits for a timeout. If I call SyncWithDatastore() from the UI thread then the NameChanged event would fire, then the PhoneChanged event and this would be fine and could be handled along the way on the UI thread, the problem is that the UI thread is blocked until the method completes. If I fire it on a worker thread, then the event handlers execute on the worker thread, if I invoke these onto the UI thread I can't then have a handler like this: void HandleNameChanged() { this.Text = this.Person.Name; } because calling into the Person.Name getter may cause the UI to block (assuming it is thread safe, if it's not thread safe then this would be a really bad idea anyway). So I'm really trying to figure out a way that I can have my cake and eat it too. I don't really want to create a business model that throws state with its events, because I'd be uselessly creating objects in scenarios where my business objects don't need to run in a thread safe manner, I guess too because I've never seen anyone else do this. :P The other idea that I'm entertaining is that rather than invoking the events, I just stash the event delegates on a FIFO queue and then dispatch them all once the worker thread returns (in the UI thread on EndInvoke for example), this second option is kind of attractive, because it is more 'atomic' in the sense that if I fail half way through I can decide whether I want to dispatch the events or not, etc. (although that seems like it might start getting really complicated). I guess for this simple example, the properties wouldn't be locked for very long at all, so maybe it is OK to just invoke the event onto the UI thread and then read out of the model, assuming that it probably isn't locked and if it is it won't be for long. But some processes would lock for longer. Say for example (and this may be a really poor example, or a bad thing to do) I had another business object that had hooked the PhoneChanged event for some reason, and this event was going to run on the worker thread, say the first event the worker thread fires is for the UI control, then as it is invoked onto the UI it races the invocation of the next handler, if the next handler wins, it might run some long running process and the UI is now blocked. Or perhaps not, if the events are invoked outside the critical section.. at any rate, this problem has still got my mind in knots. I haven't seen anything that I've really groked wrt to these ideas. Does anyone have any thoughts on this, or know where I can find some good material? Basically: multithreaded MVC in WinForms. John. =================================== This list is hosted by DevelopMentorŪ http://www.develop.com Some .NET courses you may be interested in: NEW! Guerrilla ASP.NET, 17 May 2004, in Los Angeles http://www.develop.com/courses/gaspdotnetls View archives and manage your subscription(s) at http://discuss.develop.com