Click here to Skip to main content
15,895,011 members
Articles / Desktop Programming / MFC

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

Rate me:
Please Sign up or sign in to vote.
4.87/5 (22 votes)
19 Mar 2009CPOL13 min read 81.3K   2.4K   51  
A Model-View-Controller Framework that integrates with the MFC Doc/View architecture.
//------------------------------------------------------------------------------
// $Workfile: ControlledWndT.h $
// $Header: /SbjDev/SbjCore/ControlledWndT.h 3     11/12/08 2:22p Steve $
//
//	Copyright � 2008 SbjCat
// All rights reserved.
//
//
// *** Authors ***
//	 Steve Johnson
//
// $Revision: 3 $
//
//-----------------------------------------------------------------------------

#pragma once

#include "ControlledCmdTargetT.h"
#include "WndController.h"


namespace SbjCore
{
	namespace Mvc
	{
		/**
			template class wraps a CWnd or derivative to add a link to 
			a WndController class for processing messages.
			                                             			
			ControlledWndT is derived from ControlledCmdTargetT and adds 
			an override to CWnd::OnWndMsg in order to route messages 
			to the assigned WndController.  The ControlledWndT will set 
			the WndController in its constructor with a call to
			ControlledCmdTargetT::SetController. 
			
			\param _baseClass Any CWnd or derived class
		*/
		template<class _baseClass>
		class ControlledWndT : public ControlledCmdTargetT<_baseClass>
		{
		public:
			/// ctor
			ControlledWndT()
			{
			}

			/// dtor
			virtual ~ControlledWndT()
			{
				m_hWnd = NULL;
			}

		protected:
			/** routes Windows messages to the Controller.  
				
				If the Controller::HandleWndMsg method returns true, it signals that
				it has already handled the call to OnWndMsgDefault, otherwise, OnWndMsg 
				will call OnWndMsgDefault.
				
				see MFC documentation for further information on CWnd::OnWndMsg

				\return true if the message was handled, otherwise false.
			*/
			virtual BOOL OnWndMsg(UINT message,
				WPARAM wParam,					
				LPARAM lParam,					
				LRESULT* pResult)				
			{
				BOOL bRslt = false;
				try
				{
					if (message == WM_CREATE)
					{
						message = WM_CREATE;	
					}
					if (GetSafeHwnd() != NULL)
					{
						// do pre default handling
						if ((pTheController != NULL) && (message != WM_COMMAND) && (message != WM_NOTIFY))
						{ 
							WndController* pTheWndCtrlr = dynamic_cast<WndController*>(pTheController);
							if (pTheWndCtrlr->CallDefaultFirst(message))
							{
								// return _baseClass result
								bRslt = _baseClass::OnWndMsg(message, wParam, lParam, pResult);
								(void)pTheWndCtrlr->HandleWndMsg(message, wParam, lParam, pResult);
							}
							else
							{
								// return false to allow default processing
								bRslt = pTheWndCtrlr->HandleWndMsg(message, wParam, lParam, pResult);

								// do default handling
								if (!bRslt)
								{
									bRslt = _baseClass::OnWndMsg(message, wParam, lParam, pResult);
								}
							}
						}
						else
						{
							bRslt = _baseClass::OnWndMsg(message, wParam, lParam, pResult);
						}

					}
				}
				catch(...)
				{
					// ignore exceptions (I think)
				}

				return bRslt;
			}
			
			/*
				The following overrides are only here because the MFC versions called OnCmdMsg
				and OnWndMsg as CWnd::OnCmdMsg and CWnd::OnWndMsg which bypassed the overrides 
				presented in ControlledWndT.h and ControlledCmdTarget.h. 
			*/
			
			virtual BOOL OnChildNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
			{
#ifndef _AFX_NO_OCC_SUPPORT
				if (m_pCtrlSite != NULL)
				{
					// first forward raw OCM_ messages to OLE control sources
					LRESULT lResult = SendMessage(OCM__BASE+uMsg, wParam, lParam);
					if (uMsg >= WM_CTLCOLORMSGBOX && uMsg <= WM_CTLCOLORSTATIC &&
						(HBRUSH)lResult == NULL)
					{
						// for WM_CTLCOLOR msgs, returning NULL implies continue routing
						return FALSE;
					}
					if (pResult != NULL)
						*pResult = lResult;
					return TRUE;
				}
#endif

				return ReflectChildNotify(uMsg, wParam, lParam, pResult);
			}
			
			struct AFX_CTLCOLOR
			{
				HWND hWnd;
				HDC hDC;
				UINT nCtlType;
			};

			BOOL ReflectChildNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
			{
				// Note: reflected messages are send directly to CWnd::OnWndMsg
				//  and CWnd::OnCmdMsg for speed and because these messages are not
				//  routed by normal OnCmdMsg routing (they are only dispatched)

				switch (uMsg)
				{
					// normal messages (just wParam, lParam through OnWndMsg)
				case WM_HSCROLL:
				case WM_VSCROLL:
				case WM_PARENTNOTIFY:
				case WM_DRAWITEM:
				case WM_MEASUREITEM:
				case WM_DELETEITEM:
				case WM_VKEYTOITEM:
				case WM_CHARTOITEM:
				case WM_COMPAREITEM:
					// reflect the message through the message map as WM_REFLECT_BASE+uMsg
					return OnWndMsg(WM_REFLECT_BASE+uMsg, wParam, lParam, pResult);

					// special case for WM_COMMAND
				case WM_COMMAND:
					{
						// reflect the message through the message map as OCM_COMMAND
						int nCode = HIWORD(wParam);
						if (OnCmdMsg(0, MAKELONG(nCode, WM_REFLECT_BASE+WM_COMMAND), NULL, NULL))
						{
							if (pResult != NULL)
								*pResult = 1;
							return TRUE;
						}
					}
					break;

					// special case for WM_NOTIFY
				case WM_NOTIFY:
					{
						// reflect the message through the message map as OCM_NOTIFY
						NMHDR* pNMHDR = (NMHDR*)lParam;
						int nCode = pNMHDR->code;
						AFX_NOTIFY notify;
						notify.pResult = pResult;
						notify.pNMHDR = pNMHDR;
						return OnCmdMsg(0, MAKELONG(nCode, WM_REFLECT_BASE+WM_NOTIFY), &notify, NULL);
					}

					// other special cases (WM_CTLCOLOR family)
				default:
					if (uMsg >= WM_CTLCOLORMSGBOX && uMsg <= WM_CTLCOLORSTATIC)
					{
						// fill in special struct for compatiblity with 16-bit WM_CTLCOLOR
						AFX_CTLCOLOR ctl;
						ctl.hDC = (HDC)wParam;
						ctl.nCtlType = uMsg - WM_CTLCOLORMSGBOX;
						//ASSERT(ctl.nCtlType >= CTLCOLOR_MSGBOX);
						ASSERT(ctl.nCtlType <= CTLCOLOR_STATIC);

						// reflect the message through the message map as OCM_CTLCOLOR
						BOOL bResult = OnWndMsg(WM_REFLECT_BASE+WM_CTLCOLOR, 0, (LPARAM)&ctl, pResult);
						if ((HBRUSH)*pResult == NULL)
							bResult = FALSE;
						return bResult;
					}
					break;
				}

				return FALSE;   // let the parent handle it
			}
		};

	}
}

//*** Modification History ***
// $Log: /SbjDev/SbjCore/ControlledWndT.h $
// 
// 3     11/12/08 2:22p Steve
// Finished Generalization of Model  v2.0.1

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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


Written By
SBJ
United States United States
Real name is Steve Johnson. Programming since 1979. Started on a Heathkit Micro with a DEC LSI-11 and UCSD Pascal. Moved to PCs & DOS as soon as Turbo Pascal became available. Did some Assembly, ISR, TSR etc. All this while working for a Manufacturing Co. for 8 years. Had my own solo Co. doing barcode labeling software for 4 years (terrible business man, all I wanted to do was code). Since then working for various software companies. Moved to Windows around the time of 3.1 with Borland C then C++. Then on to VC++ and MFC, and just about anything I could get my hands on or had to learn for my job, and been at it ever since. Of course recently I've been playing with .NET, ASP, C#, WPF etc.

Comments and Discussions