Posted by Jeff Clausius Thu, 29 Oct 2009 14:04:00 GMT
My name is Jeff Clausius, one of the developers at SourceGear. I would like to give you guys a “behind the scenes” look at issues encountered during the development of SourceGear products. The topics here may be very narrowly defined, focusing solely on subject matter that may not appeal to everyone. But having products based in C/C++, C#, Java, MFC, and SQL Server, we should have enough variety to cover a broad range of subjects.
With out further ado, today I present -
SourceOffSite 5 : Command Routing for CDockablePane (MFC)
One of the more challenging development pieces of SourceOffSite 5 (SOS) was to provide Document-View (Doc-View) functionality with classes inherited from the CDockablePane class. CDockablePane is great for providing a small window that can either be docked in a dock site or included in a tabbed pane. However, the class itself does not participate in the Doc-View architecture and does not handle messages for ON_COMMAND(), ON_COMMAND_RANGE(), ON_UPDATE_COMMAND_UI() and ON_UPDATE_COMMAND_UI_RANGE() generated from other areas of your MFC application. This presented a problem since we wanted the “Folder View” of SOS to reside in exactly that type of window.
At first it was thought we could create a class using multiple inheritance of CView and CDockablePane, but since each class derives from CWnd, it was undefined what would happen with messaging having two classes both deriving from CWnd, and this idea was quickly abandoned.
Creating a class derived from CView and then implementing the features of CDockablePane was another option, but we decided against this as the time it would take (and bugs we could possibly introduce) would be too great implementing CDockablePane functionality.
In the end, we went back to the drawing board looking for an easy way to get messages over to the CDockablePane classes. We finally turned to one of the slickest features of MFC - Command Routing.
With command routing, “windows messages are usually sent to the main frame window, but command messages are then routed to other objects. The framework routes commands through a standard sequence of command-target objects, one of which is expected to have a handler for the command. Each command-target object checks its message map to see if it can handle the incoming message.” This would be perfect for the needs of SOS.
Since SourceOffSite’s MDI windows consisted of one class for CMDIFrameWnd and one base class of CMDIChildWnd for the other SOS MDI children, we were able to interject our own routing handler into the base classes of these windows at ::OnCmdMsg(). The code first sent the message to any dockable panes which registered themselves with the main application within their own OnCreate(). The CMDI*Wnd::OnCmdMsg() would then send the message onto the base classes if the message was un-handled by any Pane. In regards to the classes inherited from CDockablePane, a m_pDocument member and GetDocument() method were added similar to any CView derived class, and the ::OnCmdMsg() methods ended up routing messages directly to the document’s OnCmdMsg().
I’m not sure this was the most elegant solution to the problem, but in the end we ended up with a framework of classes (with some interdependencies) that was able to use Document-View message handling with CDockablePane based classes.