删除组合框中最后输入的字符

时间:2013-10-25 19:22:10

标签: c# wpf combobox

我在这里遇到了另一个问题。

我已经设置了我的comboBox,只接受那些与comboBoxItems中任何项目名称匹配的字符。

现在我遇到了问题。请看一下我的代码然后我会解释你的问题:

private void myComboBox_KeyUp(object sender, KeyEventArgs e)
    {
        // Get the textbox part of the combobox
        TextBox textBox = cbEffectOn.Template.FindName("PART_EditableTextBox", cbEffectOn) 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 shouldRemoveLastChar = true;

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

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

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

在最后一个if条件中,我从组合框中删除了最后一个字符。但是用户可以使用箭头键或鼠标来改变光标的位置,并在文本的中间输入文本。

因此,如果在文本中间输入一个字符,如果文本无效,我的意思是如果它与ComboBox中的Items不匹配,那么我应该删除最后输入的字符。有人可以建议我如何获取最后插入的字符并将其删除吗?

更新:

string OldValue = "";

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

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

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

    OldValue = textBox.Text;

    bool shouldReplaceWithOldValue = true;

    string NewValue = textBox.Text.Insert(textBox.CaretIndex,e.Key.ToString()).Remove(textBox.CaretIndex + 1,textBox.Text.Length - textBox.CaretIndex);

    for (int i = 0; i < items.Count; i++)
    {
        // legal character input
        if (NewValue != "" && items.ElementAt(i).StartsWith(NewValue, StringComparison.InvariantCultureIgnoreCase))
        {
            shouldReplaceWithOldValue = false;
            break;
        }
    }

    //// illegal character input
    if (NewValue != "" && shouldReplaceWithOldValue)
    {
        e.Handled = true;
    }

}

这里我试图移动KeyDown事件中的所有代码来解决上述问题。这段代码工作正常,但有一个问题。

如果我有任何名为Birds&amp; amp;动物然后在键入鸟类和空格后我无法输入&amp;。

我知道问题是什么,但不知道解决方案。

问题是:输入&amp;我必须按shift键然后按7键。但两者都是以不同的密钥发送的。

我想到的解决方案: 1)我应该将我的代码移动到KeyUp事件。但是这里会出现长按和快速打字的问题。 2)我想我应该用某种东西取代e.Key。但不知道是什么。

3 个答案:

答案 0 :(得分:2)

而不是KeyUp事件,请在TextChanged ComboBox上订阅Textbox个活动。在事件处理程序中,您可以获取发生更改的偏移量。您可以在hanlder中使用验证逻辑,如果文本无效,则删除偏移处的字符。

     private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        TextBox textBox = cbEffectOn.Template.FindName("PART_EditableTextBox", cbEffectOn) as TextBox;
        textBox.TextChanged += new TextChangedEventHandler(textBox_TextChanged);
    }

    void textBox_TextChanged(object sender, TextChangedEventArgs e)
    {
        int index = e.Changes.First().Offset;
    }

答案 1 :(得分:2)

我不确定这是不是你想要做的事情,但我觉得你正在尝试做我们在视觉工作室中看到的那些我们输入的结果中的结果。

您应该使用WPF提供的验证机制,而不是删除击键。以下是一个如何运作的示例。

涵盖的场景:

  1. 输入完全匹配了一个combox项目:TypedInput&amp; SelectedItem显示完全匹配。
  2. 输入部分匹配某个元素:TypedInput将弹出列表列入短名单。绑定显示匹配的文本,而SelectedItem保持为空。
  3. 输入与列表中的任何项目都不匹配,无论是从开始还是在某些项目 随机点:用户在视觉上给予反馈(有可能 添加额外的反馈信息)与典型的红色轮廓。该 TypedInput仍然是最后一次有效输入,SelectedItem可能或可能 取决于最后一个TypedInput是否与任何项匹配,不为空。
  4. 完整代码:

    MainWindow.xaml

    <Window x:Class="Sample.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:l="clr-namespace:Sample"
            Title="MainWindow" Height="350" Width="525" 
            DataContext="{Binding Source={x:Static l:MainWindowViewModel.CurrentInstance}}">
        <StackPanel>
            <TextBlock>
                <Run Text="Typed valid text" />
                <Run Text="{Binding TypedText}"/>
            </TextBlock>
            <TextBlock>
                <Run Text="Valid SelectedItem" />
                <Run Text="{Binding SelectedItem}"/>
            </TextBlock>
            <ComboBox ItemsSource="{Binding FilteredItems}" IsEditable="True" IsTextSearchEnabled="False" SelectedItem="{Binding SelectedItem}">
                <ComboBox.Text>
                    <Binding Path="TypedText" UpdateSourceTrigger="PropertyChanged">
                        <Binding.ValidationRules>
                            <l:ContainsValidationRule />
                        </Binding.ValidationRules>
                    </Binding>
                </ComboBox.Text>
            </ComboBox>
        </StackPanel>
    </Window>
    

    MainWindow.xaml.cs

    namespace Sample
    {
        public partial class MainWindow { public MainWindow() { InitializeComponent(); } }
    }
    

    ContainsValidationRule.cs - 解决方案的主要内容

    namespace Sample
    {
        using System.Globalization;
        using System.Linq;
        using System.Windows.Controls;
    
        public class ContainsValidationRule : ValidationRule
        {
            public override ValidationResult Validate(object value, CultureInfo cultureInfo)
            {
                var result = MainWindowViewModel.CurrentInstance.Items.Any(x => x.ToLower(cultureInfo).Contains((value as string).ToLower(cultureInfo)));
                return new ValidationResult(result, "No Reason");
            }
        }
    }
    

    MainWindowViewModel - 支持ViewModel Singleton

    namespace Sample
    {
        using System.Collections.Generic;
        using System.ComponentModel;
        using System.Linq;
        using System.Runtime.CompilerServices;
    
        public sealed class MainWindowViewModel : INotifyPropertyChanged
        {
            private string _typedText;
            private string _selectedItem;
            private static readonly MainWindowViewModel Instance = new MainWindowViewModel();
    
            private MainWindowViewModel()
            {
                Items = new[] { "Apples", "Apples Green", "Bananas", "Bananas & Oranges", "Oranges", "Grapes" };
            }
    
            public static MainWindowViewModel CurrentInstance { get { return Instance; } }
    
            public string SelectedItem
            {
                get { return _selectedItem; }
                set
                {
                    if (value == _selectedItem) return;
                    _selectedItem = value;
                    OnPropertyChanged();
                }
            }
    
            public string TypedText
            {
                get { return _typedText; }
                set
                {
                    if (value == _typedText) return;
                    _typedText = value;
                    OnPropertyChanged();
                    OnPropertyChanged("FilteredItems");
                }
            }
    
            public IEnumerable<string> Items { get; private set; }
    
            public IEnumerable<string> FilteredItems
            {
                get
                {
                    return Items == null || TypedText == null ? Items : Items.Where(x => x.ToLowerInvariant().Contains(TypedText.ToLowerInvariant()));
                }
            }
            public event PropertyChangedEventHandler PropertyChanged;
    
            private void OnPropertyChanged([CallerMemberName] string propertyName = null)
            {
                var handler = PropertyChanged;
                if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
    

答案 2 :(得分:1)

您是否考虑过使用字符串变量来保存组合框文本框部分中的最后一个合法文本值?

最初,此字符串为空,因为用户尚未输入任何内容,然后在处理每个KeyUp事件时,如果输入了无效字符,则使用前一个字符串值替换文本文本框;否则,现在使用新的完整字符串更新先前的字符串值;等待用户再次输入。