In my previous article I explained how one can use the Mediator Pattern together with the MVC Pattern to structure the code in a very neat way. If you did not read my previous article I would suggest that you do, since I am basing this post on the assumption that readers already read that post.
I am writing this post because some friends from WPF Disciple suggested that I use a better example for the MVC+M. I agree 100% with them since the example that I did in my previous post was not the best one I could pick up…
Today I’ve got a new problem that I want to solve using the MVC+M. As the title of the post suggest, we are going to build a File Explorer and hopefully it will look something like this.
Yea, that’s where AvalonControlsLibrary and all other projects of mine live😀
This application is very simple to explain because I would assume that everyone reading this post has used a File Explorer. Basically we have a TreeView that shows the directories and when a directory is selected the list of files in that directory show up on screen.
The problem is that we do not have a fixed list of objects. The list is generated on the fly. If we had to load all directories in memory we would have a big performance hit + I don’t want to imagine the memory consumption. So for the TreeView I used the Flyweight Design Pattern. I will not go into details of this pattern since it is not the purpose of this post, but to summarize, each node loads a dummy child so that the user can expand the items. Once an item is expanded the TreeView controller loads the child directories of the directory being expanded.
You’ll say “OK… But what does this have to do with the Mediator?”. The Mediator comes in handy for our second problem. When an item is Selected the list of files show up in the file list (on the right hand side of our application).
So the problem here is, we have a Dynamic Hierarchal List + we have a Treeview (which does not have an IsSynchronizedWithCurrentItem property that can make the underlying ICollectionView notify us with the currently selected item). Speaking of which we now don’t even have one ICollectionView, instead we have one for each level.
How can we tell the File List Controller that an item is selected without coupling it with the Tree View Controller?
The Solution (or at least, how I would do this…)
In such a case the Mediator is key, because the mediator will make the communication between the 2 controller very easy and loosely coupled. Let me first introduce the entities we have here
– DirectorySelectorController (mentioned above as TreeView contoller)
– FileSelectorController (mentioned above as File List Controller)
OK so lets’ do this… And guess what we are going to do this in 3 steps once again.
Step 1 – Publish the Directory Selected message via the Mediator
Step 2 – Register the FileSelectorController to receive a notification for the Directory Selected message.
Step 3 – Handle the Directory Selected message in the FileSelectorController and get the files to display.
Lets now talk in C#. The following is the code to do the above mentioned 3 steps.
That’s all folks …. Download the full source code to see all the rest…
Some Side notes to keep in mind
Developers are like artists. Everyone has his own style. For example, right now the Mediator implementation that I did, is using an interface driven design where you have an interface IColleague and the mediator notifies the colleagues passing the message that is being sent. One can implement a Mediator that uses strongly typed delegate so that you can avoid doing the switch statement (in the MessageNotification method) and implementing the IColleague interface for each controller. So the implementation of such a Mediator would look like this
The Colleague that want to register simple do the following
This would totally eliminate the switch statement and the ICollegue interface…
One thing that I have been discussing with some friend from WPF Disciples is, What about big systems? Would big systems have to define loads of Messages?
The answer (at least how I see it from previous experiences working with this pattern) is NO. Why? Because the messages would be only for the controllers part. The other parts of the system would not need such a thing because if the controllers can talk together, the other entities would not need to. If we take the example of the File Explorer, the Views do not need to communicate because the controllers are synchronizing with each other. The views are just reading the data from the controllers. The model does not need this system either because the model will just give data that is being requested from the controller. So, please do not misinterpret this and use this system all around because you would create a MONSTER!
Josh Smith, also pointed out a very good point. What about memory leaks? If controllers do not unregister from the mediator once that the contoller is disposed than the controller would still exist in memory. This is a fact! I did not implement an unregister in the mediator because till now I only had controllers that do not get disposed throughout the application life cycle. Yet to implement an unregister would be just a piece of cake. All you have to do is to ask the mediator to remove the reference to a specific controller when the contoller is being disposed.
Besides the Mediator, there are loads of other ways of doing this, yet I decided to stick to this one because currently I feel that this pattern is given me the flexibility I need.
I like how this works because I feel that I can have a loosely coupled and high cohesion code base.
Loosely coupled, because the controllers know nothing about each other and I can just disable or reuse one of them at any point in time.
High cohesion, because knowing that I can make controllers communicate in an easy way, I create controllers that have one responsibility.