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

标签 c# wpf combobox

我在这里有另一个问题。

我已经设置了我的组合框,它只接受那些与组合框项目中的任何项目的名称相匹配的字符。

现在我遇到了一个问题。请看看我的代码,然后我会向您解释问题:

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 中的项目不匹配,那么我应该删除最后输入的字符。谁能建议我如何获取最后插入的字符并将其删除?

更新:

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事件中的所有代码来解决上述问题。此代码工作正常但有 1 个问题。

如果我有任何名为 Birds & Animals 的项目,那么在输入 Birds 和一个空格后我无法输入 &。

我知道问题出在哪里,但不知道解决方案。

问题是:要键入 &,我必须按 shift 键,然后按 7 键。但是两者都作为不同的 key 发送。

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

最佳答案

我不确定这是否是您想要做的,但我觉得您正在尝试做我们通常在 visual studio Intellisense 中看到的事情,即在我们键入时筛选出结果。

您应该使用 WPF 提供的验证机制,而不是删除击键。以下是其工作原理的示例。

涵盖的场景:

  1. Input 完全匹配一个组合项:TypedInputSelectedItem 都显示完全匹配。
  2. Input 部分匹配某些元素:TypedInput 列出弹出列表。绑定(bind)显示匹配的文本,而 SelectedItem 保持为空。
  3. 输入与列表中的任何项目都不匹配,无论是从开始还是在某些时候 随机点:用户在视觉上得到反馈(有可能 添加额外的反馈信息)与典型的红色轮廓。这 TypedInput 仍然是最后一个有效条目,SelectedItem 可能或可能 不为 null 取决于最后一个 TypedInput 是否匹配任何项目。

完整代码:

主窗口.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>

主窗口.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 单例

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));
        }
    }
}

关于c# - 删除组合框中最后输入的字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19597843/

相关文章:

c# - Unity 新 UI 图像更改颜色不起作用

wpf - 如何在组合框中将项目设置为选中

c# - 使用 textBox_TextChanged 事件和 if 语句一起写入文本框越来越慢。

wpf - 如何在 WPF 中将组合框的样式更改为标签或超链接?

c# - 获取当前系统日期时间

c# - 处理大型下载站点的最佳方式?

c# - 是否应该使用 Reflection.Emit 将属性作为方法发出?

c# - WPF MVVM ComboBox 标记选择

Linux 上用于构建 WPF 应用程序的 .NET CI 服务器

wpf - 在 View 模型中包含 WPF 细节的优缺点