Stingray® Foundation : Chapter 8 Model View Controller : Connecting the Model, Viewport, and Controller
Connecting the Model, Viewport, and Controller
The model, viewport, and controller objects must be created and connected in order to function as a unit. The connections that must be established are listed below.
The viewport must be given pointers to the model and controller.
The viewport must be added as an observer of the model.
The controller must be given pointers to the model and viewport.
Example 80 shows how to establish the model, viewport, and controller connections. In the sample code, the OnCreate() function is a member of a frame window class that contains the viewport as a member variable. The model is assumed to be global. The viewport is created by calling the Create() member function. The handle of the parent window and the bounding rectangle of the new viewport are passed to Create(). Next, the controller is created and passed to the viewport using the SetController() function. The model is then passed to the viewport using the SetModel() function, which simultaneously stores a pointer in the viewport to the model and adds the viewport as an observer to the model. Finally, the controller is initialized by passing a pointer to the viewport and a pointer to the model to it.
Example 80 – Establishing model, viewport, and controller connections
LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&)
{
CRect rcClient;
GetClientRect(rcClient);
 
// Get a pointer to the global model object
CCanvasModel* pModel = guid_cast<CCanvasModel*>(&_CanvasModel);
 
// Create the viewport
m_View.Create(m_hWnd, &rcClient);
 
// Create the controller
CCanvasController* pCtlr = new CCanvasController();
 
// Initialize the viewport
m_View.SetController(pCtlr, true);
m_View.SetModel(pModel);
 
// Initialize the controller
pCtlr->SetViewport(&m_View);
pCtlr->SetModel(pModel);
 
return 0L;
}
An alternative to the previous scenario is to have the viewport create and initialize the controller. The CMvcViewport class defines a virtual CreateController() function that can be overridden to create and initialize a default controller for the viewport. The CreateController() function is called during the creation of the viewport, which makes it unnecessary to explicitly initialize the connections for the controller. Example 81 shows how to create and connect the model, viewport, and controller using the CreateController() function in the viewport.
Example 81 – Creating and connecting the model, viewport and controller
class CCanvasViewport : public CMvcViewport<CMvcLogicalPartImpl,
CCanvasModel,
CCanvasController>
{
public:
. . .
virtual BOOL CreateController()
{
CCanvasController* pCtlr = new CCanvasController();
pCtlr->SetViewport(this);
pCtlr->SetModel(GetModel());
SetController(pCtlr);
return TRUE;
}
. . .
};
 
LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam,
BOOL& bHandled)
{
CRect rcClient;
GetClientRect(rcClient);
// Create the viewport
m_View.Create(m_hWnd, &rcClient);
m_View.SetModel(guid_cast<CCanvasModel*>(&_CanvasModel));
return 0L;
}
CMvcComponent
The CMvcComponent class combines a model, viewport, and controller into a single object. It takes care of making the connections between the model, viewport, and controller objects and provides a single abstraction for the user to deal with. The template parameters passed into CMvcComponent are the type of model, type of viewport, and type of controller. The CMvcComponent class aggregates the model, viewport, and controller objects. The model, viewport, and controller objects are either be passed into the component or they are created automatically by CMvcComponent. CMvcComponent provides a Create() method identical to the viewport’s Create() method, which will create the model, viewport, and controller objects, if they have not already been assigned by the time Create() is called. CMvcComponent also provides an implementation of QueryGuid() which delegates to the aggregated model, viewport, and controller objects. This means that any interfaces support by the model, viewport, or controller objects are also supported by the component. The code below shows the declaration of an MVC component.
Example 82 – MVC component declaration
typedef CMvcComponent<CBullseyeModel,
CBullseyeViewport,
CBullseyeController>
CBullseyeComponent;
ATL Specifics
The CMvcAtlComponent class is extends the CMvcComponent class by mixing in CMessageMap. It overrides the ProcessWindowMessage() function it inherits from CMessageMap and translates messages into event objects and routes them to the viewport. The advantage of using CMvcAtlComponent to create MVC components is that you can add the component to an ATL message map using the CHAIN_MSG_MAP_MEMBER macro. Example 83 forwards messages to an MVC component using the CHAIN_MSG_MAP_MEMBER macro.
Example 83 – Forwarding messages to an MVC component
typedef CAtlMvcComponent<CBullseyeModel,
CBullseyeViewport,
CBullseyeController>
CBullseyeComponent;
 
. . .
 
class CMainFrame : public CFrameWindowImpl<CMainFrame>
{
. . .
 
CBullseyeComponent m_bullseye;
 
. . .
 
BEGIN_MSG_MAP(CMainFrame)
CHAIN_MSG_MAP_MEMBER(m_bullseye)
END_MSG_MAP()
 
. . .
};