MFC的文档视图结构,通过文档管理数据,通过视图显示数据,实现数据管理与数据显示的分离,是一种强大且经典的结构模式。ActiveX控件基于COM的基础,实现功能的模块化。ActiveX本身不支持文档视图结构,如果能在ActiveX控件中实现文档视图结构,那么就可以做出功能非常强大的组件。
关于如何在ActiveX控件中实现文档视图结构,网上已经有了现成的方法,我只是想对这些方法做一些解释和补充。以下是网上的关于ActiveX控件中实现文档视图结构的实现方法的博客,方法其实都是同一方法,不过讲述的稍微有些不同,大家都可以参考一下:
1. Designing ActiveX Components with the MFC Document/View Model - 李昱成的专栏 - 博客频道 - CSDN.NET
http://blog.csdn.net/l12345678/article/details/1711521
2. MFC Doc/View结构实现ActiveX控件_lyingbo_新浪博客
http://blog.sina.com.cn/s/blog_6f83fdb40101gpyk.html
3. 单文档/视图结构的ActiveX控件 - 快活鱼 - 博客园
http://www.cnblogs.com/rukeefan/archive/2007/09/05/31184.html
接下来对ActiveX控件中实现文档视图结构的方法做进一步的解释。
MFC中的文档视图结构并不只包括文档和视图,其结构为Document/View/Frame,通过Template来管理,见CWinApp的AddDocTemplate函数代码:
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CTestTemplateDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CTestTemplateView));
AddDocTemplate(pDocTemplate);
而模板类变量pDocTemplate通过文档管理器CDocManager* m_pDocManager变量管理:
void CWinApp::AddDocTemplate(CDocTemplate* pTemplate)
{
if (m_pDocManager == NULL)
m_pDocManager = new CDocManager;
m_pDocManager->AddDocTemplate(pTemplate);
}
因此,在ActiveX控件中实现文档视图结构,必须要满足以下几个条件:
1. 有相应的文档、视图和框架对象
2. 以文档、视图和框架对象为基础创建模板类对象
3. 管理模板类对象
网上的方法主要是通过CActiveXDocTemplate和CActiveXDocControl两个类来实现文档视图框架,从这两个类的名字可以看出,CActiveXDocTemplate与模板有关,CActiveXDocControl与ActiveX控件有关,事实上,CActiveXDocTemplate是管理文档、视图和框架对象的模板类,CActiveXDocControl是控件类,我们用VC6.0或者VS2008新建的ActiveX控件工程里的控件类必须从CActiveXDocControl继承过来。以上第一和第二个条件的满足,见以下的实现代码:
AddDocTemplate(new CActiveXDocTemplate(
RUNTIME_CLASS(CAxAppDoc),
RUNTIME_CLASS(CMainFrame),
RUNTIME_CLASS(CAxAppView)));
这样一来,我们就有了模板类对象。至于第三个条件,如何管理模板类对象,CActiveXDocTemplate和CActiveXDocControl这两个类并没有提供类似MFC中的文档管理器m_pDocManager来管理模板类对象,而是为控件类CActiveXDocControl添加了一个CActiveXDocTemplate的指针成员变量,并且为模板类CActiveXDocTemplate实现了一些必要的函数,保证控件类CActiveXDocControl管理模板类CActiveXDocTemplate。只要我们按照方法上讲的来组织代码,改造ActiveX控件的结构,就能正确地在ActiveX控件中实现文档视图结构,而且不会陷入MFC本身文档视图结构复杂调用关系的漩涡中。
我要补充的,就是如何管理CActiveXDocTemplate模板类,正如上面讲的,MFC中是通过文档管理器m_pDocManager来进行管理;ActiveX控件中则是通过别的方式。
首先,CActiveXDocControl控件类中有一个CActiveXDocTemplate类的指针成员变量:
CActiveXDocTemplate* m_pDocTemplate;
然后,CActiveXDocTemplate类中实现了一些必要的函数:
CFrameWnd* CreateDocViewFrame(CWnd* pParentWnd);
void SaveDocumentFile();
virtual CFrameWnd* CreateNewFrame(CDocument* pDoc,
CFrameWnd* pOther);
virtual CDocument* OpenDocumentFile(
LPCTSTR lpszPathName, BOOL bVerifyExists = TRUE);
其中,SaveDocumentFile函数实现保存文档的功能,OpenDocumentFile函数实现打开和新建文档的功能。在MFC中,新建和打开文档是通过调用CWinApp的OnFileNew和OnFileOpen函数来实现的,而这两个函数都用到了文档管理器m_pDocManager:
// WinApp features for new and open
void CWinApp::OnFileNew()
{
if (m_pDocManager != NULL)
m_pDocManager->OnFileNew();
}
/
void CWinApp::OnFileOpen()
{
ASSERT(m_pDocManager != NULL);
m_pDocManager->OnFileOpen();
}
CActiveXDocTemplate类的OpenDocumentFile函数则绕过文档管理器m_pDocManager,实现文档新建及打开的功能:
CDocument* CActiveXDocTemplate::OpenDocumentFile(
LPCTSTR lpszPathName, BOOL bVerifyExists)
{
SaveDocumentFile();
m_docFile = lpszPathName;
if (bVerifyExists)
{
DWORD dwAttrib = GetFileAttributes(m_docFile);
if (dwAttrib == 0xFFFFFFFF ||
dwAttrib == FILE_ATTRIBUTE_DIRECTORY)
{
lpszPathName = NULL;
}
}
return CSingleDocTemplate::OpenDocumentFile(
lpszPathName, TRUE);
}
管理模板类中涉及到文档管理器m_pDocManager的部分都可以通过模板类自带的函数来实现,从而绕过了文档管理器。因此,MFC的文档视图结构中的绝大多数功能,都能在ActiveX控件中模拟出来。