Prerequisites: This article is targeted
for "http://msdn.microsoft.com/visualc/">Visual C++ .NET
and the author assumes the reader
has a good understanding of C++, MFC, OLE, HTML.
What this article does: Uses HTML in
views to get feed back from the browser via connection points. It does not open
or save documents, that's for the developer to implement.
Motive
A while back I had to develop a design tool to edit form based style pages.
After completing the project, Visual Studio .NET came into BETA, my initial
thoughts after being presented with the "Start Page" was WOW, I wanted
this feature in my application, after all products like Outlook and
InstallShield had been doing this kind of UI for years (slight exaggeration)
. Previously I had spent a while writing a wrapper class
that implemented sinks from the IE browser control so I could get feed back from
actions such as mouse click, button click etc. The problem with the class I designed was
that the class was rigid and could only be used to implement start pages. Since the release of Visual C++ 7.0
I discovered a new class which allow DHTML interaction with MFC. This class is
called CDHTMLDialog
, this class had implemented a generic framework to sinks
IE Events back into MFC, but this class was limited to dialog boxes and I was surprised
that Microsoft hadn't provided a CView
based
version. What I needed was a
CDHTMLView
class. With that in mind I developed a class to do just
that!
Design
After poking around the source code that shipped with Visual C++ .NET I found
the code that implemented IHTMLElement
sinks. I then
had the basis of designing the view. Here the class diagram.
As you can see from the class schema, CDHTMLView
inherits from CView
and CDHTMLEventSink
.
CDHTMLEventSink
is a new class that ships with Visual C++
.NET,
Implementation
- Decide which view is going to be your DHTML View
- Include DHTMLView.h & DHTMLView.cpp in your project
- Edit your Views header file and add the follow code snippets in BOLD
#include "DHTMLView.h"
class CStartPrjView : public CDHTMLView
{
protected:
DECLARE_MESSAGE_MAP()
DECLARE_DHTML_EVENT_MAP()
public:
virtual void OnInitialUpdate();
}
- Now add the event map to your for view's .cpp file
BEGIN_DHTML_EVENT_MAP(CStartPrjView)
END_DHTML_EVENT_MAP()
- Once the class has been declared its time to insert some functionality. The
first thing we need to do now is to insert some Html into the view, this can be
done design your HTML and using the resource editor import a HTML file.
- Any images must be imported as resource type "2110" and name
your images as strings e.g. "StartGif".
- Open the HTML in the Resource Design mode and select your image.
- And name set your image as a resource type:
- Now we need to tie up HTML element with events, this is done by editing
the
BEGIN_DHTML_EVENT_MAP
and inserting message handlers as you would
with normal MFC message handlers. One thing to note here is the IDs I gave
each element in my document an ID. This allows me to map to the create
event.
BEGIN_DHTML_EVENT_MAP(CStartPrjView)
DHTML_EVENT_ONCLICK(_T("MRU1"), OnClickMRU1)
DHTML_EVENT_ONCLICK(_T("MRU2"), OnClickMRU1)
DHTML_EVENT_ONCLICK(_T("MRU3"), OnClickMRU1)
DHTML_EVENT_ONCLICK(_T("MRU4"), OnClickMRU1)
DHTML_EVENT_ONCLICK(_T("NewFile"), OnNewFile)
DHTML_EVENT_ONCLICK(_T("OpenFile"), OnOpenFile)
END_DHTML_EVENT_MAP()
- Now we have to wire the handlers in the header and implementation file
HRESULT OnClickMRU1(IHTMLElement *phtmlElement);
HRESULT OnClickMRU1(IHTMLElement *phtmlElement);
HRESULT OnClickMRU1(IHTMLElement *phtmlElement);
HRESULT OnClickMRU1(IHTMLElement *phtmlElement);
HRESULT OnNewFile(IHTMLElement *phtmlElement);
HRESULT OnOpenFile(IHTMLElement *phtmlElement);
HRESULT CStartPrjView::OnClickMRU1(IHTMLElement *phtmlElement)
{
CComBSTR bstr;
phtmlElement->get_innerText(&bstr);
if (bstr)
{
GetDocument()->SetTitle(CString(bstr) );
CString s;
s.Format("File %s selected", CString(bstr));
AfxMessageBox(s, MB_ICONINFORMATION);
}
return S_FALSE;
}
HRESULT CStartPrjView::OnClickMRU2(IHTMLElement *phtmlElement)
{
CComBSTR bstr;
phtmlElement->get_innerText(&bstr);
if (bstr)
{
GetDocument()->SetTitle(CString(bstr) );
CString s;
s.Format("File %s selected", CString(bstr));
AfxMessageBox(s, MB_ICONINFORMATION);
}
return S_FALSE;
}
HRESULT CStartPrjView::OnClickMRU3(IHTMLElement *phtmlElement)
{
CComBSTR bstr;
phtmlElement->get_innerText(&bstr);
if (bstr)
{
GetDocument()->SetTitle(CString(bstr) );
CString s;
s.Format("File %s selected", CString(bstr));
AfxMessageBox(s, MB_ICONINFORMATION);
}
return S_FALSE;
}
HRESULT CStartPrjView::OnClickMRU4(IHTMLElement *phtmlElement)
{
CComBSTR bstr;
phtmlElement->get_innerText(&bstr);
if (bstr)
{
GetDocument()->SetTitle(CString(bstr) );
CString s;
s.Format("File %s selected", CString(bstr));
AfxMessageBox(s, MB_ICONINFORMATION);
}
return S_FALSE;
}
HRESULT CStartPrjView::OnNewFile(IHTMLElement *phtmlElement)
{
AfxMessageBox("New file Pressed" , MB_ICONINFORMATION);
return S_FALSE;
}
HRESULT CStartPrjView::OnOpenFile(IHTMLElement *phtmlElement)
{
AfxMessageBox("Open file Pressed" , MB_ICONINFORMATION);
return S_FALSE;
}
Conclusion
The CDHTMLView
class provides a stable framework for hooking
HTML elements into your code, one thing I should add there is a whole raft of
data exchange macros to exchange data with MFC and HTML eg. DDX_DHtml_ElementInnerText.
This macros are all defined in the DHTMLView.h file.