100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
C++

MFC Controls Overview

A tour of MFC's C++ wrapper classes for Windows common controls, how to bind them via DDX_Control, and practical examples with CListCtrl and CComboBox.

Windows and DialogsBeginner9 min readJul 10, 2026
Analogies

MFC Controls Overview

MFC provides C++ wrapper classes for every standard Windows common control — CButton, CEdit, CListBox, CComboBox, CListCtrl, CTreeCtrl, CProgressCtrl, CSliderCtrl, and more — each derived from CWnd, so a control gets the same Create()/DestroyWindow()/message-map machinery as a top-level window while also exposing control-specific member functions like CListCtrl::InsertColumn() or CComboBox::AddString() that wrap the underlying LVM_/CB_ window messages.

🏏

Cricket analogy: It's like a coaching manual giving every fielding position — slip, gully, mid-on — its own specialized drill set, even though every fielder still shares the same base fitness and catching fundamentals.

Binding Controls to Data with Control and Value Variables

Class Wizard historically generated two kinds of member variables for a dialog control: a 'control' variable of the wrapper type (e.g., CListBox m_lstNames) that gives direct access to the control's own API, and a 'value' variable (e.g., CString m_strSelected) hooked through DDX for simple get/set access; using the control variable directly is necessary whenever you need functionality DDX doesn't expose, such as CListCtrl::SetItemState() for multi-selection or CComboBox::SetItemData() for storing an associated pointer per entry.

🏏

Cricket analogy: It's like a captain sometimes reading a simple scoreboard summary for a quick glance, but pulling up the full ball-by-ball data feed when they need granular detail like exact field placements per delivery.

Common Controls in Practice

CListCtrl and CComboBox Examples

CListCtrl supports several visual styles via SetExtendedStyle() such as LVS_EX_FULLROWSELECT and LVS_EX_GRIDLINES, and populating a report-style list involves InsertColumn() for headers followed by InsertItem() and SetItemText() for rows, while CComboBox distinguishes CBS_DROPDOWN (editable text plus a list) from CBS_DROPDOWNLIST (selection-only, no free typing), a style choice that directly affects whether users can enter values not present in the list.

🏏

Cricket analogy: It's like choosing between a scoreboard that only shows preset totals versus one that lets the scorer manually key in a rare event like a penalty run not covered by the standard buttons.

cpp
// In DoDataExchange:
DDX_Control(pDX, IDC_LIST_NAMES, m_lstNames);   // control variable
DDX_Control(pDX, IDC_COMBO_CITY, m_cboCity);

// OnInitDialog:
BOOL CMyDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    m_lstNames.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
    m_lstNames.InsertColumn(0, _T("Name"), LVCFMT_LEFT, 150);
    m_lstNames.InsertColumn(1, _T("Score"), LVCFMT_RIGHT, 80);

    int idx = m_lstNames.InsertItem(0, _T("Ada Lovelace"));
    m_lstNames.SetItemText(idx, 1, _T("98"));

    m_cboCity.AddString(_T("Bengaluru"));
    m_cboCity.AddString(_T("Chennai"));
    m_cboCity.SetCurSel(0);   // CBS_DROPDOWNLIST — user can only pick, not type

    return TRUE;
}

Every common control wrapper still exposes SendMessage()/SendDlgItemMessage() escape hatches — if a wrapper class is missing a specific member function for a rarer control message, you can always send the raw LVM_/CB_/TCM_ message directly and get the same effect.

Calling control member functions like InsertColumn() before the control's HWND exists (e.g., in the constructor instead of OnInitDialog() or after DDX_Control has run) will fail silently or assert, because the CWnd wrapper has no attached window handle yet at that point.

  • Every standard Windows common control has an MFC wrapper class derived from CWnd (CButton, CEdit, CListCtrl, CComboBox, etc.).
  • Control wrapper classes expose typed member functions that internally send the appropriate window messages (LVM_, CB_, TCM_, etc.).
  • DDX_Control binds a 'control' variable of the wrapper type for direct API access, distinct from a simple DDX 'value' variable.
  • CListCtrl needs InsertColumn() for headers and InsertItem()/SetItemText() for rows in report view.
  • CComboBox's CBS_DROPDOWN allows free typing; CBS_DROPDOWNLIST restricts selection to the existing list.
  • Control member functions require a valid HWND, so they must run after DDX_Control/creation, typically in OnInitDialog().
  • Raw SendMessage() calls remain available as an escape hatch for control messages the wrapper class doesn't expose.

Practice what you learned

Was this page helpful?

Topics covered

#MFCMicrosoftFoundationClassesStudyNotes#MicrosoftTechnologies#MFCControlsOverview#MFC#Controls#Binding#Data#StudyNotes#SkillVeris#ExamPrep