WPF ComboBox使用IsEditable="True"属性时,如何指示未找到匹配项?

7

以以下简单文本框为例:

<ComboBox IsEditable="True" SelectedItem="{Binding}">
    <ComboBoxItem>Angus/ComboBoxItem>
    <ComboBoxItem>Jane</ComboBoxItem>
    <ComboBoxItem>Steve</ComboBoxItem>
</ComboBox>

我希望允许用户通过输入名称来查找他们的选择,因此我将IsEditable设置为true。绑定到SelectedItem属性的可接受值是列表中的任何一个选项或没有选择(null)。问题是,默认情况下,如果有人键入不在列表中的名称,则没有错误指示。

例如:用户可以键入“Bob”,导致SelectedItem属性为null,但没有意识到Bob不存在于列表中。相反,我想在ComboBox的Text属性不为null或空,并且SelectedItemnull时立即提供视觉指示,并阻止他们继续输入。

我的初步想法是自定义验证规则,但我不知道如何访问组合框的Text和SelectedItem属性。

我的WPF老师在课程中多次强调的一个提示是:在WPF中,你绝不能直接使用SelectedItem。这就是集合视图存在的意义。 - Ilya Kogan
3个回答

3
作为一个初学者,您可能希望让用户看到他们是否正在输入可用选项之一。
1)在网上搜索“自动完成组合框”。
2)查看以下内容:

http://weblogs.asp.net/okloeten/archive/2007/11/12/5088649.aspx

http://www.codeproject.com/KB/WPF/WPFCustomComboBox.aspx

3) 也可以尝试这个:

    <ComboBox IsEditable="true" TextSearch.TextPath="Content">
        <ComboBoxItem Content="Hello"/>
        <ComboBoxItem Content="World"/>
    </ComboBox>

上面的代码片段是一种提供“视觉指示”的原始方法。如果用户输入'h',则'hello'将出现在输入文本框中。然而,这本身没有机制阻止用户输入非法字符。
4)这是一个更高级的版本:
    <ComboBox Name="myComboBox" IsEditable="true" KeyUp="myComboBox_KeyUp">
        <ComboBoxItem Content="Hello"/>
        <ComboBoxItem Content="World"/>
        <ComboBoxItem Content="WPF"/>
        <ComboBoxItem Content="ComboBox"/>
    </ComboBox>

代码后台:

    private void myComboBox_KeyUp(object sender, KeyEventArgs e)
    {
        // Get the textbox part of the combobox
        TextBox textBox = myComboBox.Template.FindName("PART_EditableTextBox", myComboBox) as TextBox;

        // holds the list of combobox items as strings
        List<String> items = new List<String>();

        // indicates whether the new character added should be removed
        bool shouldRemove = true;

        for (int i = 0; i < myComboBox.Items.Count; i++)
        {
            items.Add(((ComboBoxItem)myComboBox.Items.GetItemAt(i)).Content.ToString());
        }

        for (int i = 0; i < items.Count; i++)
        {
            // legal character input
            if(textBox.Text != "" && items.ElementAt(i).StartsWith(textBox.Text))
            {
                shouldRemove = false;
                break;
            }
        }

        // illegal character input
        if (textBox.Text != "" && shouldRemove)
        {
            textBox.Text = textBox.Text.Remove(textBox.Text.Length - 1);
            textBox.CaretIndex = textBox.Text.Length;
        }
    }

在这里,一旦我们检测到没有任何组合框项目以文本框中的文本开头,我们就不让用户继续输入。我们会删除添加的字符并等待另一个字符。

这段代码存在一个错误 - 用户按住某个键不放时,代码只会删除最后一个字符。(例如,如果用户按住 f 键直到输入了 5 个 'f',则文本中将添加 4 个 'f')。但我目前还没有解决方案。 - RB.

2

这个解决方案是基于 user1234567 的答案,做了几处修改。它不再搜索“Items”列表,而是简单地检查ComboBox的 SelectedIndex 是否大于等于 0,以判断是否找到匹配项,并解决了 RB 关于按键长按插入多个字符的问题。它还添加了一个声音反馈来拒绝输入非法字符。

private int _lastMatchLength = 0;

private void myComboBox_GotFocus(object sender, RoutedEventArgs e)
{
    _lastMatchLength = 0;
}

private void myComboBox_KeyUp(object sender, KeyEventArgs e)
{
    ComboBox cBox = sender as ComboBox;

    TextBox tb = cBox.Template.FindName("PART_EditableTextBox", cBox) as TextBox;
    if (tb != null)
    {
        if (cBox.SelectedIndex >= 0)
        {
            _lastMatchLength = tb.SelectionStart;
        }
        else if (tb.Text.Length == 0)
        {
            _lastMatchLength = 0;
        }
        else
        {
            System.Media.SystemSounds.Beep.Play();
            tb.Text = tb.Text.Substring(0, _lastMatchLength);
            tb.CaretIndex = tb.Text.Length;
        }
    }
}

1

这是一个不错的解决方案,直到下拉框中有很多记录。我会这样做:

在文件顶部声明此内容

List<String> items = new List<String>(); 

private void myComboBox_KeyUp(object sender, KeyEventArgs e) 
{ 
  TextBox textBox = myComboBox.Template.FindName("PART_EditableTextBox", myComboBox) as TextBox; 

     // indicates whether the new character added should be removed 
    bool shouldRemove = true; 

    // this way you don't fill the list for every char typed
    if(items.Count <= 0)
    { 
       for (int i = 0; i < myComboBox.Items.Count; i++) 
       { 
           items.Add(((ComboBoxItem)myComboBox.Items.GetItemAt(i)).Content.ToString()); 
       } 
    }
    // then look in the list
    for (int i = 0; i < items.Count; i++) 
    { 
        // legal character input 
        if(textBox.Text != "" && items.ElementAt(i).StartsWith(textBox.Text)) 
        { 
            shouldRemove = false; 
            break; 
        } 
    } 

    // illegal character input 
    if (textBox.Text != "" && shouldRemove) 
    { 
        textBox.Text = textBox.Text.Remove(textBox.Text.Length - 1); 
        textBox.CaretIndex = textBox.Text.Length; 
    } 
} 

除非绑定是持续向组合框添加记录,否则我认为这是更有效的查找。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接