> Or you may want to take a look at Microsofts asynchronous application > block
I've spent an hour or two sort of looking through the code for this, but haven't got too heavily involved with it. I guess the reason I didn't get to stuck into it is that I don't really want asynchronous processing. I just need it to keep my UI alive while I do synchronous processing.. Also, I'm particularly interested from the point of view of 'in-process' rather than out-of-process or across the wire processing. I'll have a closer look though, now that you've bought it up. > >> multithreaded MVC in WinForms > > MVC (Model View Controller) comes from Smalltalk and is a pattern for > decoupling view, controller and application model. In ASP.NET for > example the code behind file is the controller, .aspx (with only render > code) is the view and the model is what ever you want it to be. Often > the controller and view are implemented as the same class - WinForm > implementation > Another pattern usually used with MVC is the observer > (publish/subscribe) pattern which enables the model to inform the views > of changes. When used with MVC the model is the subject and the view is > the observer. The observer provides an implementation of an Update > function which the subject then calls. So, the idea is when the model > changes any views subscribed will be notified via their Update methods. > This pattern was used in MFC (yuck!) - may remember it being called DDX, > DDV. > > Some catalogues say that the Update method of the observer should accept > a subject as one of the parameters. Whilst I don't disagree with this I > do think it can be misleading. In a multithreaded environment it could > be a potential disaster to pass a reference to the model (the subject). > An alternative to passing a reference to the model is to use a push > replication strategy. Here the model calls Update of the observer, but > passes the 'changed' data 'by value' (a message). The view can then > decide which bits it needs. This is easier than a pull model (reference) > where the view would have to go get the data from the 'thread-safe' > model Yep. I understand and agree with your explanation here. Passing state isn't feasible for two reasons: A. there could be *lots* of state, and cloning it 'just in case' for every message is just not an option B. state may not be available. You're right in saying that I can't pass a reference to the model because of the locking problems (or complexities), i.e. deadlocks, blocked UI, or bogus data. An example of B would be if I had code that specified: this.Project.ClientId = 42; This could cause a Project.ClientChanged event. When this event is handled by an interested view, it might want to do something like this: this._clientNameTextBox.Text = this.Project.Client.Name; or perhaps: this._clientControl.Client = this.Project.Client; since all that has happened in the client application is that the project's ClientId has been specified, I would need to 'load' Client 42 by requesting it from the application server. I don't want to load the Client if no view is going to want it (the view might only want to specify this._clientIdTextBox.Text = this.Project.ClientKey.Id.ToString(); for example) but I need to be able to load it if it is required. But I don't want to load it on the UI thread where the view is being updated. So for this reason, neither of the two solutions above really suite what I want to do, given this don't-block-the-UI-thread requirement. My intended strategy for dealing with this is have the view then queue a request for data, so the application thread will get it when it next works on the model. In turn the application thread will need to alert the view that the data is now available by queuing the event for when the UI thread next gets to read from the model. This alert is an implementation detail, I could throw the ClientChanged event again, or throw a ClientLoaded event, or a RelatedDataLoaded event with an enum, or whatever, the point is that getting the data is not explicitly done by the view, getting the long-running code off the UI thread.. but like I said, I haven't got an implementation yet, and am really just looking for some direction on how to go about this. > > 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 > > Combining delegates together would give you this functionality. If you > define your delegate with byRef parameters each delegate will be able to > modify the data. This is quite useful if you need to pass data from one > method to another in a chained manner (synchronously) - chain of command > > > > this.Name = GetNameFromWebService(this.Id); > > > this.Phone = GetPhoneFromDatabase(this.Id); > > Never, never do this type of stuff in a distributed application - if > you're an OO purist I apologize, but put simply don't extend OO thinking > when it comes to remote communication. > Fine granular calls like this are the killers are all applications (okay > blame RPC!), but if you take the same thinking that good OO design means > lots of getters and setters - forget it. It won't scale. In remoting > situations we place a course grained interface 'remote façade' onto the > remote object. This interface has methods like GetPerson, SetPerson etc > > I know this is just an example that you're using (so I don't mean to > rant at you personally ;-) Heh, just to remove any lingering doubt: I was simply trying to fabricate a reason why I might have a NameChanged and PhoneChanged event triggered synchronously in a long-running operation. There is no way that I would go across the wire for just a simple property like 'Name'. :P But I am happy to use blocking calls (RPC) to get the data that I need. If you think about the implication of the queued system that I discussed in my last post I could actually use this to my advantage to limit my round trips. If 'load requests' were added by the UI thread, then when the application thread gets a chance to service the 'command queue' it might be feasible for it to look through the command list and process all Create/Update/Delete commands first, then dispatch all Retrieve operations to the application server in one hit. They all need to be serviced, and they all need to return data before other processing can continue, so they might as well all be serviced at the same time. Of course, meddling with the 'order' of commands (i.e. altering the FIFO order) might be bad for some reason that I haven't completely thought through yet (if subsequent operations are going to require that data for example).. at the very least Retrieve operations that weren't separated by other commands could be packaged into one request.. 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