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

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

  1. Begin a project using the MFC ActiveX Control Wizard.

  2. Right-click the interface node for your control.

    This opens the shortcut menu.

  3. From the shortcut menu, click Add and then click Add Property.

  4. 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.

  5. 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

  1. Load your control's project.

  2. On the Control Settings page, select a window class for the control to subclass. For example, you may want to subclass an EDIT control.

  3. Load your control's project.

  4. Right-click the interface node for your control.

    This opens the shortcut menu.

  5. From the shortcut menu, click Add and then click Add Property.

  6. Type the property name in the Property Name box. Use MyProp for this example.

  7. Select a data type from the Property Type drop-down list box. Use short for this example.

  8. For Implementation Type, click Get/Set Methods.

  9. 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.

  10. Click Finish.

  11. 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();
    }
    
  12. The parameter passed to the BoundPropertyChanged and BoundPropertyRequestEdit functions is the dispid of the property, which is the parameter passed to the id() attribute for the property in the .IDL file.

  13. 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;
    
  14. 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);
    }
    
  15. 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;
    
  16. Make the following line the last line in the DoPropExchange function:

    PX_String(pPX, _T("MyProp"), m_strText);
    
  17. Modify the OnResetState function so that it contains the following code:

        COleControl::OnResetState();  // Resets defaults found in DoPropExchange
       m_strText = AmbientDisplayName();
    
  18. 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.

See Also

Reference

Data-Bound Controls (ADO and RDO)

Concepts

MFC ActiveX Controls