【问题标题】:CComboBox DDX_CBString behavior confusingCComboBox DDX_CBString 行为令人困惑
【发布时间】:2016-03-15 16:21:34
【问题描述】:

我在对话框中使用 ComboBox 控件为用户提供一些有用的值(例如:10;20;100;400;800),但如果需要,让用户插入确切的值。

我很久以后才发现: 如果我在 Combobox 中键入值 40,则 Combobox 在 UpdataData() 之后总是返回 400。 :(( 值 3941 的其他值没有问题。

这不是我和用户所期望的行为。
当我输入一个值时,ComboBox 应该取这个值,如果从下拉菜单中选择,取这个。

我现在看到这种行为是由 DDX_CBString 给出的。

我必须自己编写 DDX_CBString 还是有其他方法?

代码:

void CTestDialog::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_IFBANDWIDTH, m_cIFBandWidth);
    DDX_CBString(pDX, IDC_IFBANDWIDTH, m_sIFBandWidth);  // Bahavior confusing
}

BOOL CTestDialog::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    m_cIFBandWidth.ResetContent();

    m_cIFBandWidth.AddString(_T("10"));
    m_cIFBandWidth.AddString(_T("20"));
    m_cIFBandWidth.AddString(_T("100"));
    m_cIFBandWidth.AddString(_T("400"));
    m_cIFBandWidth.AddString(_T("800"));


    return TRUE;  // return TRUE unless you set the focus to a control
    // EXCEPTION: OCX Property Pages should return FALSE
}

void CTestDialog::OnBnClickedApply()
{   
    UpdateData(TRUE);     // m_sIFBandWidth now 4 ok!
    UpdateData(FALSE);    // m_sIFBandWidth still 4, but control show 400, so the next OnOk() or Apply() take this value. Wrong!
}

【问题讨论】:

  • 如果您尝试使用 GetCurSel 方法获取当前索引,然后使用 GetLBText 方法获取该索引处的文本,会发生什么情况?那么结果如何呢?
  • 您应该发布适当的代码来显示您与组合框的交互,而不是我们猜测。
  • @AndrewTruckle:在上面的代码示例中:在 ComboBox 中输入 4 后,GetCurSel 为 3,GetLBText 为“400”。这不是我所期望的,它应该仍然是 4。
  • 组合是基于零的索引。 0, 1, 2, 3。所以 3 是位置 4,其文本值为 400。
  • 是的,从程序的角度来看,这是克莱尔,而不是用户的角度。用户输入 4 得到 400!

标签: mfc


【解决方案1】:

我通过修改 DDX_CBstring 解决了这个问题。

void DDX_CBString_Normal(CDataExchange* pDX, int nIDC, CString& value)
{
    ..    
    if (pDX->m_bSaveAndValidate)
    {
        ..      
    }
    else
    {
        // Behaviour as we expect: Type a value and keep it
        // Select it form dropwon, or take the value the user type it
        AfxSetWindowText(hWndCtrl, value);
        return; 

        /* Disable original MS behavior 
        // set current selection based on model string
        if (::SendMessage(hWndCtrl, CB_SELECTSTRING, (WPARAM)-1,
            (LPARAM)(LPCTSTR)value) == CB_ERR)
        {
            // just set the edit text (will be ignored if DROPDOWNLIST)
            AfxSetWindowText(hWndCtrl, value);
        } 
       */
    }
}

如果有人有其他方法,请告诉我。

【讨论】:

  • 如果您查看选择字符串方法msdn.microsoft.com/en-us/library/30ft9e54.aspx 的文档,它提到:仅当字符串的初始字符(从起点开始)时才会选择字符串。
  • 所以应该是FindStringExact,然后根据索引选择。否则,设置窗口文本。 DDX 系统中的错误。
  • 40,不在列表中。但是400是。所以 selectstring 选择它。
  • 好吧,一个 DDX 错误,但为什么 MS 不修复它?
【解决方案2】:

旧问题的新答案:您不必编写自己的 DDX 处理程序,但这不是错误。 DDX_CBString 有意进行部分字符串比较,而提供 DDX_CBStringExact 进行精确字符串比较。 MSDN docs 并不能很好地解释差异,所以我同意它令人困惑。

您可以手动将行更改为:

DDX_CBStringExact(pDX, IDC_IFBANDWIDTH, m_sIFBandWidth);

【讨论】:

  • 我在这个非常意外的行为上遇到了同样的问题(当新值是列表框中现有值的前缀子字符串时,文本框字符串不更新)。谢谢,这个解决方案很好地解决了它。
猜你喜欢
  • 2011-11-09
  • 1970-01-01
  • 1970-01-01
  • 2015-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多