
Last week traveling from Utrecht back to Enschede I finally got a good idea on how I can use the composite UI application Block in my open source scheduling application.
In the training OOUML, Erma talked about building a specialized class that serves as a controller for a specific use case. This idea got me thinking about the combination of workitems, controllers and the MVC model in general. I tried several combinations and came up with the following idea.
The composite UI application block uses separate a assembly for each module in the application. Within each module you can define one or more workitems that get initialized by a module init class. Within a workitem you can then use the MVC model as normal.
My idea however is a bit different, I like the idea of having a separate assembly for each module, as this makes it easier to update small parts of the whole application instead of distributing the application over and over again. In vision a module has one workitem which serves as the application controller, managing state between use cases that are implemented in the module. The workitem will create some views that will serve as the application views and are thus shared between use cases. The commands that the user executes from the views are handled by the workitem which will start a new controller if it needs to start a use case. The controller will now serve as a use case controller and handle one separate use case. This way the code is nicely separated and way easier to maintain, as there are less methods in one class and the code gets less cluttered. It is possible that a use case needs a specific view, this is fine and the controller may create this view at any time during the execution of the use case.
I also got a tip for developers wanting to work with application block and having trouble getting the MVC model to work. The best method to invoke commands on the controller is to use the Command pattern that is implemented in the application block. Let the controller/workitem create the view and the controller and just implement the following on the view:
[InjectionConstructor]
Public MyView([ServiceDependency]WorkItem workItem) {
workItem.Commands["MyCommand"].AddInvoke(myButton,"Click");
}
This will register a button on the view to be the invoker of the command MyCommand. Now you only have to do the following on the controller:
[CommandHandler("MyCommand")]
Public void HandleMyCommand(object sender,EventArgs e) {
//Do something
}
This will register a method on the controller to handle the command for you. Passing data between the view and the controller is a bit more tricky, the best way to do this is to Create the view first and then the controller, after that you simply assign the view to a property of the controller. This way the controller can always query the view for the necessary data to perform a specific task. Another trick I used here is to only provide the controller with the interface of the view, not the implementing class. This will keep the coupling between the view and the controller loose.
Attached to this post you will find a small collaboration diagram that may help to clarify the whole thing a bit. It helped me getting it clear how the various parts of a module work together to implement a specific part of the application.