锐英源软件
第一信赖

精通

英语

开源

擅长

开发

培训

胸怀四海 

第一信赖

当前位置:锐英源 / 英语翻译 / MFC模型-视图-控制器实现介绍
服务方向
人工智能数据处理
人工智能培训
kaldi数据准备
小语种语音识别
语音识别标注
语音识别系统
语音识别转文字
kaldi开发技术服务
软件开发
运动控制卡上位机
机械加工软件
软件开发培训
Java 安卓移动开发
VC++
C#软件
汇编和破解
驱动开发
联系方式
固话:0371-63888850
手机:138-0381-0136
Q Q:396806883
微信:ryysoft

锐英源精品开源心得,转载请注明:“锐英源www.wisestudy.cn,孙老师作品,电话13803810136。”需要全文内容也请联系孙老师。

An Introduction to a Model-View-Controller Implementation for MFC

MFC模型 - 视图 - 控制器实现介绍

small shapes

For Those Of You Who Are Interested...

I have posted the following articles in the series describing the MVC Framework.

    The SBJ MVC Framework - The Model, from Abstraction to Realization

    The SBJ MVC Framework - The Design View, Responding to Model Change

对于那些感兴趣的...

我已经发布了一系列描述MVC框架下面的文章。

    SBJ MVC框架 - 模型,从抽象到实现

    SBJ MVC框架 - 设计视图,响应模式变化
Table of Contents

    Introduction

    The Source Code

    The MVC Framework

        Controlling CCmdTarget and CWnd

        MessageHandler Classes

        Controller Classes

        The Model and Events

    Conclusion

    TODO

    History 

目录

   介绍

   源代码

   MVC框架

      CCmdTarget的控制和CWnd

      MessageHandler类

      控制器类

      模型和事件

   结论

   TODO

   历史

Introduction

In the Model-View-Controller architectural pattern, the Model represents the application data, the View, the visual components that present the data to the user, and the Controller manages the user's interactions with the various input devices and interprets how they should affect the Model. Once affected, the Model informs the View of the need to update its presentation to the user. That's a rather simplistic explanation; however, if you want a more complete explanation, there are many good articles and books explaining the MVC pattern and the motivations behind its design. One very good source can be found in the Wikipedia .
介绍

在模型 - 视图 - 控制器架构模式中,模型表示应用程序的数据,视图,显示给用户的视觉组件,控制器管理的各种输入装置的用户的交互,解释它们应如何影响模型。一旦受到影响,模块通知需要更新其呈现给用户的视图。这是一个相当简单的解释;但是,如果你想要一个更完整的解释,有很多好的文章和书籍解释了MVC模式和其设计背后的动机。一个非常好的来源可以在维基百科中找到。

As anyone with MFC experience can tell you, its Document/View architecture is a variation of the MVC pattern. In MFC, the CDocument class represents the Model, and the CView class represents both the View and the Controller. Obviously, the Model-View-Controller Framework presented in this article will bring back the separation of View and Controller to the MFC application.

任何有MFC经验的人都可以告诉你,它的文档/视图结构是MVC模式的变化。在MFC中,CDocument类代表模型,CView类代表两个视图和控制器。显然,在这篇文章中提到的模型 - 视图 - 控制器架构将带回视图和MFC应用程序控制器的分离。

I have used aspects of the MVC Framework in existing MFC applications with years of legacy code as well as with new MFC Feature Pack AppWizard created applications. The point I make here is that the Framework does not disrupt the existing Doc/View architecture, and can be implemented unobtrusively over time. Old code can be incrementally refactored to use the new MVC architecture while still using the existing Doc/View architecture.

我已经使用有多年的遗留代码的MFC应用程序MVC框架方面以及新的MFC功能包应用程序向导创建应用程序。我再这里提出的一点是,框架不会破坏现有的文档/视图结构,并且可以随着时间的推移悄悄地实施。旧的代码可以逐步重构以使用新的MVC架构,同时仍然使用现有的文档/视图结构。

I don't consider the Framework to be complete by any means, as you will see in the TODO section at the bottom of the article; however, I have completed enough to illustrate the underlying concepts. This article introduces the Framework by presenting the classes that form the Framework base that integrates with the MFC Doc/View architecture.

我不认为框架该通过任何方式完成,你会在文章底部的TODO部分看到;但是,我已完成充分说明基本概念。这篇文章通过展示集成MFC文档/视图架构形成框架的基类介绍了框架。

The Source Code

The source code provided with this article is contained in a VS2008 solution, SbjDev, with three projects:

    SbjCore - The foundation DLL

    XmlMvc - A DLL that contains MVC Framework extensions that support an XML Model

    Shapes - The sample EXE
源代码

本文提供的源代码包含在VS2008的解决方案,SbjDev,有三个项目:

    SbjCore - 基础DLL

    XmlMvc - 包含支持XML模式MVC框架扩展名的DLL

    形状 - 样品EXE

The approach I've taken is that any code that could be used in any application should go into SbjCore. Any code that is specific to an XML implementation of the MVC Framework should go into XmlMvc, and only code which is specific to the application should go into the application. Granted, I'm not always successful, and sometimes, I don't see the generalities in the code that can be factored down to the lower levels, but that has been my intent.

我采取的方法是,可以在任何应用程序中使用的任何代码应该进入SbjCore。任何代码特定于实现了MVC XML框架应该进入XmlMvc,只有代码是特定于应用程序的应该进入该应用程序。当然,我并不总是成功的,有时候,我看不出它们可以被分解下降到较低级别的代码的概论,但那一直是我的意图。

SbjCore.dll

The MVC Framework is part of the foundation DLL, SbjCore.dll. The code is all namespaced, and to some degree, the structure of the namespaces is mimicked in the structure of the Visual Studio Project where it resides. Not surprisingly, the root is the namespace SbjCore, and all of the MVC code is in SbjCore::Mvc. Along with the MVC Framework, SbjCore also contains a large number of utility components, many of which were influenced by CodeProject articles, for helping deal with a wide variety of common programming tasks such as Memory, Strings, Images, the Clipboard, etc. There are also components that implement an Event architecture, DragNDrop, UndoRedo, and more. As I said, anything that can be used in any application goes here.

SbjCore.dll

MVC框架是基础DLL,SbjCore.dll的一部分。该代码是所有的命名空间,一定程度上,命名空间的结构是在模仿Visual Studio项目存在结构。这并不奇怪,根是命名空间SbjCore,所有的MVC代码是SbjCore ::mvc。随着MVC框架,SbjCore还包含了大量实用工具组件,其中许多是受CodeProject文章的影响,协助处理各种常见编程任务,如内存,字符串,图像,剪贴板等方面。还有组件实现一个事件架构,DragNDrop,UndoRedo,和更多的组件。正如我所说的,可以在任何应用程序中使用的放在这里。

XmlMvc.dll

The XmlMvc.dll uses the MSXML6 implementation of the Document Object Model (DOM), which provides an ideal base of generic routines for handling an XML Model. All XML extensions to the MVC Framework are contained in this separate DLL. In general, the XmlMvc Model makes the assumption that XML elements are like records in a database and XML attributes are like the fields of the record. In this way, it's able to generalize a lot of code that might have ended up application specific.

Other technologies that one would use to implement a Model such as ADO, SQL, or proprietary DBs would be treated in the same way.
XmlMvc.dll

XmlMvc.dll使用MSXML6实现文档对象模型(DOM),它提供了通用例程的理想基地用于处理XML模式。所有扩展到MVC框架的XML都包含在这个单独的DLL。一般情况下,做个假设XmlMvc模型中XML元素就像数据库中的记录,XML属性像记录的字段。以这种方式,它能够概括很多可能已经结束了具体的应用程序代码。 其他将用于实现一种模型如ADO,SQL或专有数据块技术将用同样的方式进行处理。

Shapes.exe

Shapes.exe is a rudimentary drawing program created using the MFC Feature Pack AppWizard that integrates the MVC Framework and XmlMvc Model extensions with its base MFC Doc/View architecture.
Shapes.exe

Shapes.exe是使用MFC功能包应用程序向导,基础MFC文档/视图结构集成了MVC框架和XmlMvc模型扩展创造出的一个基本的绘图程序。

An existing Shapes.xml file is provided as an illustration of what XML file format the Shapes application expects. As you can see from the listing below, under the Shapes document element is an element called Drawing, which contains elements of type Rectangle and Ellipse. Each of these has a number of attributes which describe its appearance when displayed in the main View of the application.

现有的Shapes.xml文件是作为Shapes应用程序预期XML文件格式的说明。你可以从下面的清单中看到,Shapes文档元素下是所谓的绘画元素,其中包含矩形和椭圆元素。每个元素都有一些属性,在应用程序的主视图中描述其外观。

Shapes.xml
<?xml version="1.0" encoding="utf-8"?>
<Shapes>
<Drawing name="Test Drawing">
<Rectangle label="The First Rectangle" left="250" top="250" right="750" bottom="750"
borderRGB="255" borderWidth="9" fillRGB="128"/>
<Rectangle label="Blue Rectangle" left="100" top="90" right="200" bottom="200"
borderRGB="16711680" borderWidth="1" fillRGB="16711680"/>
<Ellipse label="The First Ellipse" left="300" top="200" right="800" bottom="400"
borderRGB="65280" borderWidth="1" fillRGB="65280"/>
</Drawing>
</Shapes>

As you would assume, the Shapes application provides the user with the ability to add, delete, modify, and move individual and multiply selected Rectangles and Ellipses. As illustrated in the screenshot at the beginning of the article, the application contains the Main Design View and two Docking Panes: an Explorer Tree View of the Drawing and a Property Grid showing the attributes of the selected shape.

正如你所假想,图形应用程序提供了添加,删除,修改,移动单独的或组合的矩形和椭圆形给用户。本文开头的说明截图,该应用程序包含主设计视图和两个对接窗格:一个绘制资源管理器树视图和显示所选形状属性的属性网格。

The MVC Framework

If you've used MFC at all, you should be familiar with the way the CDocument class informs its list of CView classes of the need to update through calls to each CView::OnUpdate method. You should also be familiar with how the CCmdTarget and CWnd classes handle messages through their message maps and handler methods. So, rather than going into detail describing the MFC implementation, I'll provide an overview of the Framework and its base components, with the focus on how they integrate with the Doc/View architecture.

MVC框架

如果你完全使用MFC,你应该熟悉Document类通知,需要通过调用每个CView :: OnUpdate中的方法来更新CView类名单的方式。你还应该熟悉CCmdTarget和的CWnd类如何通过他们的消息映射和处理方法处理消息。因此,不是进入详细描述MFC实现,我会提供框架及其基本组件的概况,重点是如何对他们的文档/视图架构整合。

Controlling CCmdTarget and CWnd

The key to the integration is the ability to selectively hijack the Windows messages sent to the CCmdTarget and CWnd classes before they are processed by the default MFC message map and routing implementation. This is accomplished by two classes.
CCmdTarget和CWnd的控制

整合的关键是在它们被默认MFC消息映射和路由执行处理发送到CCmdTarget和CWnd类之前有选择地挟持Windows消息的能力。这是通过两个类来实现的。

template<class _baseClass>
class ControlledCmdTargetT : public _baseClass

项目位置:SbjCore / MVC / ControlledCmdTargetT.h

template<class _baseClass>
class ControlledWndT : public ControlledCmdTarget<_baseClass>

项目位置:SbjCore / MVC / ControlledWndT.h

The ControlledCmdTargetT class overrides the OnCmdMsg method of its CCmdTarget derived _baseClass, and the ControlledWndT class additionally overrides the OnWndMsg method of its CWnd derived _baseClass. These overrides direct the incoming messages first to an assigned Controller class for handling before letting the standard MFC message map processing to occur.

该ControlledCmdTargetT类重写CCmdTarget它的OnCmdMsg方法得出_baseClass和ControlledWndT类。覆盖其CWnd派生_baseClass方法的OnWndMsg。这些覆盖直接传入消息首先到指定控制器类让标准的MFC消息映射处理发生前处理。

By using a template base class, these classes can derive respectively from any CCmdTarget or CWnd derived class. For instance...

使用模板的基类,这些类可以从任何CCmdTarget或CWnd派生类分别获得。例如...

class ControlledDocument : public ControlledCmdTargetT<CDocument>
class ControlledView : public ControlledWndT<CView>
MessageHandler Classes

How Windows messages are handled is a major difference between the MFC Doc/View architecture and the MVC Framework. In the Framework, message handlers are not methods of a CCmdTarget or CWnd class as they are in the Doc/View, but are classes in their own right. There are three basic variations, all deriving from a base MessageHandler class, each handling a different type of Windows message.

MessageHandler类

如何将Windows消息处理是MFC文档/视图结构和MVC框架之间的一个主要区别。在该框架,消息处理程序不是CCmdTarget或CWnd类方法,因为它们是在文档/视图,但是他们自身的类。有三种基本的变化,都是从基MessageHandler类派生,每个处理不同类型的Windows消息。

MessageHandler

    CmdMsgHandler - WM_COMMAND

    NotifyMsgHandler - WM_NOTIFY

    WndMsgHandler - other WM_XXX

MessageHandler

    CmdMsgHandler - WM_COMMAND

    NotifyMsgHandler - WM_NOTIFY

    WndMsgHandler - 其他WM_XXX

CmdMsgHandler, NotifyMsgHandler, and WndMsgHandler are all pure virtual, and it is always one of these that provide the base for the actual concrete handlers. The MessageHandler base class is never directly derived from. Also, the Message ID is not directly assigned to the handler, rather it is mapped to the handler when it is added to a Controller.

CmdMsgHandler,NotifyMsgHandler和WndMsgHandler都是纯虚拟的,它始终是这些提供基础的实际具体的处理程序之一。该MessageHandler的基类是不能直接派生而来。此外,消息ID不直接分配给该处理程序,而它被映射到时,它被添加到一个控制器的处理程序。

Class MessageHandler

MessageHandler provides the base for the CmdMsgHandler, NotifyMsgHandler, and WndMsgHandler classes. In addition to providing common base for the derived classes, MessageHandler also provides a chaining mechanism so derived Controllers can provide MessageHandler classes for the same message ID, allowing them to access previously assigned MessageHandler classes. This is similar to the way MFC method based message handlers access base class method handlers. When assigned to a Controller, the Controller calls MessageHandler::Initialize with itself as the Controller, and if there is one, the last previously assigned MessageHandler. CmdMsgHandler, NotifyMsgHandler, and WndMsgHandler provide methods for calling previous handlers they have been assigned.

class AFX_EXT_CLASS MessageHandler
{ 
public:    MessageHandler();  
virtual ~MessageHandler();  
public:    void Initialize(Controller* pCtrlr, MessageHandler* pPrevHandler);
Controller* GetController() const;  
protected:    MessageHandler* GetPrevHandler) const;
private:    struct MessageHandlerImpl* const m_pImpl; 
};

Project location: SbjCore/Mvc/MessageHandler.h 项目位置: SbjCore/Mvc/MessageHandler.h

MessageHandler 类

MessageHandler 为CmdMsgHandler,NotifyMsgHandler和WndMsgHandler类提供基础。

除了为派生类提供共同的基础,MessageHandler还提供了一个链接机制,以便控制器可为来自同一消息ID的MessageHandler类,允许他们访问先前分配的MessageHandler类。这类似于MFC根据消息处理程序访问基类的方法处理方式的方法。当分配一个控制器,控制器调用MessageHandler ::自身初始化为控制器,并且如果有一个,前面最后一次分配的MessageHandler。 CmdMsgHandler,NotifyMsgHandler和WndMsgHandler提供方法调用他们被分配以前的处理程序。

Class CmdMsgHandler

CmdMsgHandler is an abstract class for handling WM_COMMAND messages. The CmdTargetController calls the public Handle methods of the CmdMsgHandler for handling not only the CmdMsg variation, but also the CmdUI variation of messages. The private OnHandleCmd method is a pure virtual, and must be implemented in the derived class. The OnHandleCmdUI method has a default implementation that returns true for the CCmdUI::Enable method of the passed CCmdUI. To support the functionality derived from its base MessageHandler class for the chaining of handlers, derived OnHandleCmd and OnHandleCmdUI methods should call the public methods HandleCmdPrev and HandleCmdUIPrev, as appropriate.

class AFX_EXT_CLASS CmdMsgHandler : public MessageHandler
{
public:
virtual ~CmdMsgHandler();
CmdTargetController* GetController() const;
public:
bool HandleCmd(EventID nID);
bool HandleCmdUI(CCmdUI* pCmdUI);
bool HandleCmdPrev(EventID nID);
bool HandleCmdUIPrev(CCmdUI* pCmdUI);
private:
virtual bool OnHandleCmd(EventID nID) = 0;
virtual bool OnHandleCmdUI(CCmdUI* pCmdUI);
};

Project location: SbjCore/Mvc/CmdMsgHandler.h

Class NotifyMsgHandler

NotifyMsgHandler is an abstract class for handling WM_NOTIFY messages. The private

OnHandleNotify method is a pure virtual, and must be implemented in the derived

class. To support the functionality derived from its base MessageHandler class for

the chaining of handlers, derived OnHandleNotify methods should call the public

method HandleNotifyPrev, as appropriate.

class AFX_EXT_CLASS NotifyMsgHandler : public MessageHandler
{
public:
virtual ~NotifyMsgHandler();
CmdTargetController* GetController() const;
public:
bool HandleNotify(NMHDR* pNMHDR, LRESULT* pResult);
bool HandleNotifyPrev(NMHDR* pNMHDR, LRESULT* pResult);
private:
virtual bool OnHandleNotify(NMHDR* pNMHDR, LRESULT* pResult) = 0;
};

Project location: SbjCore/Mvc/NotifyHandler.h

Class WndMsgHandler

WndMsgHandler is an abstract class for handling all the rest of the Windows messages. The private OnHandleWndMsg method is a pure virtual, and must be implemented in the derived class. To support the functionality derived from its base MessageHandler class for the chaining of handlers, derived OnHandleWndMsg methods should call the public method HandleWndMsgPrev, as appropriate. Provision is made for calling the MFC default message handling first. The OnCallDefaultFirst method, by default, returns false; however, derived classes may override this to return true where appropriate.

class AFX_EXT_CLASS WndMsgHandler : public MessageHandler
{
public:
virtual ~WndMsgHandler();
WndController* GetController() const;
public:
LRESULT HandleWndMsg(WPARAM wParam, LPARAM lParam, LRESULT* pResult);
bool HandleWndMsgPrev(WPARAM wParam, LPARAM lParam, LRESULT* pResult);
bool CallDefaultFirst();
private:
virtual LRESULT OnHandleWndMsg(WPARAM wParam,
LPARAM lParam, LRESULT* pResult) = 0;
virtual bool OnCallDefaultFirst();
};

Project location: SbjCore/Mvc/WndMsgHandler.h

Controller Classes

In the MVC Framework, one of the roles the Controller plays is that of a message manager for the ControlledCmdTargetT or ControlledWndT to which it is assigned by maintaining a map of MessageHandler objects. When a ControlledCmdTargetT or ControlledWndT class passes a message to its Controller class, the Controller uses the ID of the message to look for a handler in its map, and if found, it gives the handler a chance to respond. If no handler is found, or the handler wishes for the message to continue to be handled, the base class of the Controlled class is given a chance. In most cases, this will be a CmdTarget or CWnd derived class with a standard MFC message map implementation. It is in this way that the Framework integrates seamlessly with the existing MFC implementation.

As with the MessageHandler classes, there is a base Controller class, and in this case, just two base derivatives: CmdTargetController and WndController.

    Controller

        CmdTargetController

        WndController

Class Controller

Controller provides a base for the CmdTargetController and WndController classes. It is responsible for maintaining the map of MessageHandler classes for its Controlled class. It has methods for adding and removing handlers from its map, and an accessor to get the current handler for a given ID. This is used internally to chain handlers for the same ID.

You'll notice a method PrepareCtxMenu. Derived Controller classes are queried through this method in response to the WM_CONTEXTMENU message as to what menu items should be added to the current invocation of the Context Menu.

Project location: SbjCore/Mvc/Controller.h

Class CmdTargetController

class AFX_EXT_CLASS Controller
{
public:
Controller();
virtual ~Controller();
public:
void Initialize();
public:
void AddHandler(EventID nID, MessageHandler* p);
void AddHandler(EventID nFirstID, EventID nLastID, MessageHandler* p);
void RemoveHandler(EventID nID);
void RemoveHandler(EventID nFirstID, EventID nLastID);
MessageHandler* GetHandler(EventID nID) const;
SbjCore::Utils::Menu::ItemRange PrepareCtxMenu(CMenu& ctxMenu) const;
private:
virtual void OnInitialize();
virtual SbjCore::Utils::Menu::ItemRange OnPrepareCtxMenu(CMenu& ctxMenu) const;
private:
struct ControllerImpl* const m_pImpl;
}; 

The CmdTargetController class controls ControlledCmdTargetT classes. It handles the mapping of the CmdMsgHandler and NoftifyMsgHandler classes. When the ControlledCmdTargetT receives a message, its OnCmdMsg method determines, in the same way that MFC does, which flavor of message it is. It then calls the appropriate CmdTargetController::HandleCmdMsg, CmdTargetController::HandleCmdUIMsg, or CmdTargetController::HandleNotifyMsg method. If the message is not handled, it then calls CmdController::RoutCmdMsg, giving the controller a chance to override the default MFC routing. If the message still isn't handled, or warrants further processing, the base class of the ControlledCmdTargetT is given a chance.

In this class, you'll see the GetUndoRedoMgr method. Explanation of this is really beyond the scope of this article; however, the SbjCore::Mvc::DocController derived from CmdTargetController assigns the SbjCore::UndoRedo::Manager to the task, and it is implemented in full in the Shapes.exe application.

class AFX_EXT_CLASS CmdTargetController : public Controller
{
public:
CmdTargetController();
virtual ~CmdTargetController();
public:
void SetCmdTarget(CCmdTarget* p);
CCmdTarget* GetCmdTarget() const;
public:
bool RoutCmdMsg(EventID nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo);
UndoRedo::Manager* GetUndoRedoMgr() const;
public:
bool HandleCmdMsg(EventID nID);
bool HandleCmdUIMsg(EventID nID, CCmdUI* pCmdUI);
bool HandleNotifyMsg(NMHDR* pNMHdr, LRESULT* pResult);
private:
virtual bool OnRoutCmdMsg(EventID nID,
int nCode,
void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo);
virtual UndoRedo::Manager* OnGetUndoRedoMgr() const;
private:
struct CmdTargetControllerImpl* const m_pImpl;
};

Project location: SbjCore/Mvc/CmdTargetController.h

Class WndController

The WndController class controls the ControlledWndT classes. It handles the mapping of the WmdMsgHandler classes. Of course, since it is derived from CmdTargetController, it can also handle CmdMsgHandler and NotifyHandler classes.

As you know from handling Windows messages in MFC, it is sometimes appropriate to call the base class handler before processing the Windows message in your handler. To provide for this, when the ControlledWndT receives a message, its OnWndMsg method calls the WndMsgController::CallDefaultFirst method, which in turn queries the handler map for an entry, and if found, asks the handler if default processing should pcede the call to it. Of course, if the message is not handled, or warrants further processing, the base class of the ControlledWndT is given a chance.

class AFX_EXT_CLASS WndController :  public CmdTargetController
{
public:
WndController();
virtual ~WndController();
public:
void SetWnd(CWnd* p);
CWnd* GetWnd() const;
public:
BOOL HandleWndMsg(EventID message, WPARAM wParam,
LPARAM lParam, LRESULT* pResult);
bool CallDefaultFirst(EventID message);
private:
struct WndControllerImpl* const m_pImpl;
};

The Model and Events

Rather than using the CView::OnUpdate method, the MVC Framework instead uses an Event architecture. Each time the Model changes, an Event is fired, indicating the type of change that has occurred. Event handlers are registered for a given type of change, and respond when the Event is fired. Unlike the MFC Doc/View architecture, the Event architecture is not limited to CView and derivative classes, and can be utilized by any object interested in Model change.

Uniquely Identifying an Event

Events are identified by unique ID values which are created using Joseph M. Newcomer's RegisterWindowMessage technique [^] that I've been using forever.

DECLARE_EVENT_ID macro

#define DECLARE_EVENT_ID(name, guid) DECLARE_USER_MESSAGE(name, guid)

Project location: SbjCore/EventMgr/EventMgr.h

Namespace EventMgr

The Event architecture is not actually part of the MVC Framework as it can be used independently. Rather, the namespace SbjCore::EventMgr contains the functions and classes that make up the Event architecture.

EventMgr maintains a private map of registered EventHandler classes which are keyed by unique ID.

typedef UINT EventID;

EventHandler classes register themselves with the private EventMgr handler map during construction, and unregister when destructed. When an Event class with a matching ID key is fired, its NotifyHandlers method will call each registered EventHandler::Handle method, passing a pointer to itself. Listed below are the various components of the Event architecture.

Class Event

The Event class is pretty straightforward. When fired, it notifies its handlers

class AFX_EXT_CLASS Event
{
public:
Event();
Event(EventID nEventID, bool bAutoFire = true);
virtual ~Event();
public:
void Init(EventID nEventID, bool bAutoFire = true);
void NotifyHandlers();
private:
struct EventImpl* const m_pImpl;
};

Project location: SbjCore/EventMgr/EventMgr.h

Class EventT

The EventT class provides a generic derivation of Event through which handlers can receive any specific data necessary for processing the event.

template <class T>
class EventT : public Event
{
T theData;
public:
EventT(EventID nEventID, T data, bool bAutoFire = true) :
Event(nEventID, false), // must auto fire after fully constructed
theData(data)
{
if (bAutoFire) // now we can auto fire
{
NotifyHandlers();
}
}
virtual ~EventT()
{
}
T GetData() const
{
return theData;
}
};

Project location: SbjCore/EventMgr/EventT.h

Fire Function

The Fire function provides a convenient way to fire an event when the only information the handler needs is the fact that the event happened.

AFX_EXT_API void Fire(EventID nEventID);

Project location: SbjCore/EventMgr/EventMgr.h

Class EventHandler

EventHandler is an abstract base class. Derived classes must implement the private virtual method OnHandle which is called from the public method Handle. EventHandler classes register themselves with the EventMgr handler map on construction, and unregister on destruction.

class AFX_EXT_CLASS EventHandler
{
public:
EventHandler(EventID nEventID);
virtual ~EventHandler();
public:
void Handle(Event* pEvent);
private:
virtual void OnHandle(Event* pEvent) = 0;
private:
struct EventHandlerImpl* const m_pImpl;
};

Project location: SbjCore/EventMgr/EventMgr.h

AbortException

AbortException provides a way for handlers to short circuit the fire mechanism. When thrown by a handler, the Event::NotifyHandlers method will stop firing the event to subsequent handlers.

typedef CUserException AbortException;

Project location: SbjCore/EventMgr/EventMgr.h

Conclusion

In the preceding sections, I've introduced the classes that provide the base functionality of the MVC Framework, and shown how they integrate with the MFC Doc/View architecture. From these classes, the Framework is extended by providing ControlledCmdTargetT and ControlledCWndT derivatives and associated Controller classes for the main components of an MFC application. From these, the XmlMvc.dll provides extensions that support an XML Model implementation. If there is interest, future articles will explore the specific application of the Framework to CDockablePane types and the controls they contain, the sample DesignView and XML Model used in the Shapes.exe, and the reusable aspects of these components. All of this is contained in the source code provided with this article, so, run Shapes.exe and explore the code in the application and DLLs. I think you'll be surprised at how little code is actually at the application level.

TODO

    Support for all common controls

    Support for MFC CView derivatives

    Implement DocTemplate derivatives for CDockablePane

    Complete generalization based on ModelItemHandle

History

    2008 Oct. 20 - Original article submitted

    2008 Nov. 24 - Added link to follow up article

    2009 Mar. 19 - Added link to second follow up article

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

友情链接
版权所有 Copyright(c)2004-2021 锐英源软件
公司注册号:410105000449586 豫ICP备08007559号 最佳分辨率 1024*768
地址:郑州大学北校区院(文化路97号院)内