WPF Filtered Combobox问题

时间:2018-04-09 16:59:23

标签: c# wpf combobox filtering

我试图实现我在此处找到的自定义组合框控件:

https://stackoverflow.com/a/48559118

(由于声誉不佳,我无法发表评论)

此自定义组合框用于根据文本输入过滤组合框中的项目。

除了一件事,解决方案大多数都有效。当用户在组合框中键入文本时,然后选择一个条目,不再可以从代码隐藏中执行SelectedItem = xyz(与绑定相同的问题,想要制作一个简单的示例来重现问题)。

示例代码:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        var testLst = new List<string>(new string[] { "element1", "element2", "element3" });

        cmbTest.ItemsSource = testLst;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        cmbTest.SelectedItem = "element1";
    }
}

Xaml:

<Window x:Class="TestList.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:TestList"
        xmlns:mycontrol="clr-namespace:MyControls"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <StackPanel Width="150" Height="150" Orientation="Vertical">
            <mycontrol:FilteredComboBox x:Name="cmbTest"  IsEditable="True" IsTextSearchEnabled="False" StaysOpenOnEdit="True" >
            </mycontrol:FilteredComboBox>
            <Button Content="SelectItem" Click="Button_Click"></Button>
        </StackPanel>
    </Grid>
</Window>

我认为问题可能与列表不再包含该项目的事实有关,因为它已被过滤掉了?!

我很难找到在自定义控件中修复此问题的方法。

修改,自定义控制代码:

using System.Collections;
using System.Diagnostics;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;

namespace MyControls
{
    public class FilteredComboBox : ComboBox
    {
        private string oldFilter = string.Empty;

        private string currentFilter = string.Empty;

        protected TextBox EditableTextBox => GetTemplateChild("PART_EditableTextBox") as TextBox;


        protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
        {
            if (newValue != null)
            {
                var view = CollectionViewSource.GetDefaultView(newValue);
                view.Filter += FilterItem;
            }

            if (oldValue != null)
            {
                var view = CollectionViewSource.GetDefaultView(oldValue);
                if (view != null) view.Filter -= FilterItem;
            }

            base.OnItemsSourceChanged(oldValue, newValue);
        }

        protected override void OnPreviewKeyDown(KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.Tab:
                case Key.Enter:
                    IsDropDownOpen = false;
                    break;
                case Key.Escape:
                    IsDropDownOpen = false;
                    SelectedIndex = -1;
                    Text = currentFilter;
                    break;
                default:
                    if (e.Key == Key.Down) IsDropDownOpen = true;

                    base.OnPreviewKeyDown(e);
                    break;
            }

            // Cache text
            oldFilter = Text;
        }

        protected override void OnKeyUp(KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.Up:
                case Key.Down:
                    break;
                case Key.Tab:
                case Key.Enter:

                    ClearFilter();
                    break;
                default:                                        
                    if (Text != oldFilter)
                    {
                        var temp = Text;
                        RefreshFilter(); //RefreshFilter will change Text property
                        Text = temp;

                        if (SelectedIndex != -1 && Text != Items[SelectedIndex].ToString())
                        {
                            SelectedIndex = -1; //Clear selection. This line will also clear Text property
                            Text = temp;
                        }


                        IsDropDownOpen = true;

                        EditableTextBox.SelectionStart = int.MaxValue;
                    }

                    //automatically select the item when the input text matches it
                    for (int i = 0; i < Items.Count; i++)
                    {
                        if (Text == Items[i].ToString())
                            SelectedIndex = i;
                    }

                    base.OnKeyUp(e);                    
                    currentFilter = Text;                    
                    break;
            }
        }

        protected override void OnPreviewLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
        {
            ClearFilter();
            var temp = SelectedIndex;
            SelectedIndex = -1;
            Text = string.Empty;
            SelectedIndex = temp;
            base.OnPreviewLostKeyboardFocus(e);
        }

        private void RefreshFilter()
        {
            if (ItemsSource == null) return;

            var view = CollectionViewSource.GetDefaultView(ItemsSource);
            view.Refresh();
        }

        private void ClearFilter()
        {
            currentFilter = string.Empty;
            RefreshFilter();
        }

        private bool FilterItem(object value)
        {
            if (value == null) return false;
            if (Text.Length == 0) return true;

            return value.ToString().ToLower().Contains(Text.ToLower());
        }
    }
}

0 个答案:

没有答案