MFC: MDI singleton doc/view application

What singleton means? In our case it’s MDI application where the user can’t have more than one document of a given type open at any time. In order to implement this in doc/view fashion we need 2 things.

First we need a public member in our CDocument delivered class that when called will tell us whatever view of supplied type already exists. Here is the implementation of this public member function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
 * @brief Check's if given view is already loaded.
 * @param rtClass - the runtime class of the view.
 */
BOOL CVPhoneBookDoc::NeedViewCreation(CRuntimeClass *rtClass)
{
	POSITION pos = GetFirstViewPosition();
	while(pos != NULL)
	{
		CView *pView = GetNextView(pos);
		if(pView->GetRuntimeClass() == rtClass)
		{
			CMDIChildWnd * pViewFrame = (CMDIChildWnd *)pView->GetParentFrame();
			((CMDIFrameWnd*)AfxGetMainWnd())->MDIActivate(pViewFrame);
			return FALSE; // Already exists
		}
	}
 
	return TRUE; // Allow creation
}

The function iterates over the views associated with the document and try’s to find one that’s match our supplied run-time class. If match is found the view is activated and FALSE is returned. Else view creation is allowed.

Second we need to implement a custom member function, for example in the CWinApp delivered class that will be called as replacement of OnNewDocument() or OnOpenDocument(). Here is an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
void CVPhoneBookApp::OnCreateContactVeiw()
{
	POSITION curTemplatePos = GetFirstDocTemplatePosition();
 
	while(curTemplatePos != NULL)
	{
		CDocTemplate* curTemplate =
			GetNextDocTemplate(curTemplatePos);
		CString str;
		curTemplate->GetDocString(str, CDocTemplate::docName);
		if(str == _T("Contacts"))
		{
			// We have only one document for template "Contacts"
			POSITION docPos = curTemplate->GetFirstDocPosition();
			if(docPos == NULL)
			{
				curTemplate->OpenDocumentFile(NULL);
			}
			else
			{
				CVPhoneBookDoc *pDoc = (CVPhoneBookDoc*)curTemplate->GetNextDoc(docPos);
				if(pDoc)
				{
					// Check if view of this type exists
					if(pDoc->NeedViewCreation(RUNTIME_CLASS(CContactsView)))
					{
						curTemplate->OpenDocumentFile(NULL);
					}
				}
			}
		}
	}
}

When called this function first checks if document is available. If it’s not available we call CDocTemplate member function OpenDocumentFile() else, we retrieve a pointer to the document class and checks if view of requested type need’s to be created.