MFC ActiveX Controls: Using Data Binding in an ActiveX Control
The new home for Visual Studio documentation is Visual Studio 2017 Documentation on docs.microsoft.com.
The latest version of this topic can be found at MFC ActiveX Controls: Using Data Binding in an ActiveX Control.
One of the more powerful uses of ActiveX controls is data binding, which allows a property of the control to bind with a specific field in a database. When a user modifies data in this bound property, the control notifies the database and requests that the record field be updated. The database then notifies the control of the success or failure of the request.
This article covers the control side of your task. Implementing the data binding interactions with the database is the responsibility of the control container. How you manage the database interactions in your container is beyond the scope of this documentation. How you prepare the control for data binding is explained in the rest of this article.
Conceptual Diagram of a Data-Bound Control
The COleControl
class provides two member functions that make data binding an easy process to implement. The first function, BoundPropertyRequestEdit, is used to request permission to change the property value. BoundPropertyChanged, the second function, is called after the property value has been successfully changed.
This article covers the following topics:
Creating a Bindable Stock Property
Creating a Bindable Get/Set Method
Creating a Bindable Stock Property
It is possible to create a data-bound stock property, although it is more likely that you will want a bindable get/set method.
Note
Stock properties have the bindable and requestedit attributes by default.
To add a bindable stock property using the Add Property Wizard
Begin a project using the MFC ActiveX Control Wizard.
Right-click the interface node for your control.
This opens the shortcut menu.
From the shortcut menu, click Add and then click Add Property.
Select one of the entries from the Property Name drop-down list. For example, you can select Text.
Because Text is a stock property, the bindable and requestedit attributes are already checked.
Select the following check boxes from the IDL Attributes tab: displaybind and defaultbind to add the attributes to the property definition in the project's .IDL file. These attributes make the control visible to the user and make the stock property the default bindable property.
At this point, your control can display data from a data source, but the user will not be able to update data fields. If you want your control to also be able to update data, change the OnOcmCommand
OnOcmCommand function to look as follows:
#ifdef _WIN32
WORD wNotifyCode = HIWORD(wParam);
#else
WORD wNotifyCode = HIWORD(lParam);
#endif
if(wNotifyCode==EN_CHANGE)
{
if(!BoundPropertyRequestEdit(DISPID_TEXT))
{
SetNotSupported();
}
else
{
GetText();
// Notify container of change
BoundPropertyChanged(DISPID_TEXT);
}
}
return 0;
You can now build the project, which will register the control. When you insert the control in a dialog box, the Data Field and Data Source properties will have been added and you can now select a data source and field to display in the control.
Creating a Bindable Get/Set Method
In addition to a data-bound get/set method, you can also create a bindable stock property.
Note
This procedure assumes you have an ActiveX control project that subclasses a Windows control.
To add a bindable get/set method using the Add Property Wizard
Load your control's project.
On the Control Settings page, select a window class for the control to subclass. For example, you may want to subclass an EDIT control.
Load your control's project.
Right-click the interface node for your control.
This opens the shortcut menu.
From the shortcut menu, click Add and then click Add Property.
Type the property name in the Property Name box. Use
MyProp
for this example.Select a data type from the Property Type drop-down list box. Use short for this example.
For Implementation Type, click Get/Set Methods.
Select the following check boxes from the IDL Attributes tab: bindable, requestedit, displaybind, and defaultbind to add the attributes to the property definition in the project's .IDL file. These attributes make the control visible to the user and make the stock property the default bindable property.
Click Finish.
Modify the body of the
SetMyProp
function so that it contains the following code:if(!BoundPropertyRequestEdit(1)) { SetNotSupported(); return; } else { if(AmbientUserMode()) // SendMessage only at run-time { _stprintf_s(m_strText.GetBuffer(10), 10, _T("%d"), newVal); SetWindowText(m_strText); m_strText.ReleaseBuffer(); } else { InvalidateControl(); } // Signal a property change // This is the MFC equivalent of OnChanged() BoundPropertyChanged(1); SetModifiedFlag(); }
The parameter passed to the
BoundPropertyChanged
andBoundPropertyRequestEdit
functions is the dispid of the property, which is the parameter passed to the id() attribute for the property in the .IDL file.Modify the OnOcmCommand function so it contains the following code:
#ifdef _WIN32 WORD wNotifyCode = HIWORD(wParam); #else WORD wNotifyCode = HIWORD(lParam); #endif if(wNotifyCode==EN_CHANGE) { if(!BoundPropertyRequestEdit(DISPID_TEXT)) { SetNotSupported(); } else { GetText(); // Notify container of change BoundPropertyChanged(DISPID_TEXT); } } return 0;
Modify the
OnDraw
function so that it contains the following code:if(!AmbientUserMode()) { // Draw the Text property at design-time pdc->FillRect(rcBounds, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH))); pdc->DrawText(m_strText, -1, (LPRECT)&rcBounds, DT_LEFT | DT_TOP | DT_SINGLELINE); } else { DoSuperclassPaint(pdc, rcBounds); }
To the public section of the header file the header file for your control class, add the following definitions (constructors) for member variables:
CString m_strText; short m_nMyNum;
Make the following line the last line in the
DoPropExchange
function:PX_String(pPX, _T("MyProp"), m_strText);
Modify the
OnResetState
function so that it contains the following code:COleControl::OnResetState(); // Resets defaults found in DoPropExchange m_strText = AmbientDisplayName();
Modify the
GetMyProp
function so that it contains the following code:if(AmbientUserMode()) { GetWindowText(m_strText); m_nMyNum = (short)_ttoi(m_strText); } return m_nMyNum;
You can now build the project, which will register the control. When you insert the control in a dialog box, the Data Field and Data Source properties will have been added and you can now select a data source and field to display in the control.