22 Stimmen

Dynamischer Filter der WPF Combobox basierend auf Texteingabe

Ich kann nicht scheinen, eine direkte Methode für die Implementierung der Filterung von Texteingabe in eine Liste von Elementen in einer WPF Combobox zu finden.
Wenn Sie IsTextSearchEnabled auf true setzen, springt das Dropdown-Menü der Combobox auf das erste passende Element. Was ich brauche, ist für die Liste gefiltert werden, was die Textzeichenfolge übereinstimmt (z.B. Wenn ich auf meine Combobox fokussieren und geben Sie "abc", ich möchte alle Elemente in der ItemsSource Sammlung, die mit beginnen (oder enthalten vorzugsweise) "abc" als die Mitglieder der Dropdown-Liste zu sehen).

Ich bezweifle, dass es einen Unterschied macht, aber meine Anzeige Element ist eine Eigenschaft eines komplexen Typs Vorlage:

<ComboBox x:Name="DiagnosisComboBox" Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="3" 
          ItemsSource="{Binding Path = ApacheDxList,
                                UpdateSourceTrigger=PropertyChanged,
                                Mode=OneWay}"
          IsTextSearchEnabled="True"
          ItemTemplate="{StaticResource DxDescriptionTemplate}" 
          SelectedValue="{Binding Path = SelectedEncounterDetails.Diagnosis,
                                  Mode=TwoWay,
                                  UpdateSourceTrigger=PropertyChanged}"/>

Gracias.

20voto

Kelly Punkte 6544

Ich habe dies erst vor ein paar Tagen mit einer modifizierten Version des Codes von dieser Website getan: Ehre, wem Ehre gebührt

Mein vollständiger Code ist unten aufgeführt:

using System.Collections;
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)
                        {
                            RefreshFilter();
                            IsDropDownOpen = true;

                            EditableTextBox.SelectionStart = int.MaxValue;
                        }

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

Und die WPF sollte etwa so sein:

<MyControls:FilteredComboBox ItemsSource="{Binding MyItemsSource}"
    SelectedItem="{Binding MySelectedItem}"
    DisplayMemberPath="Name" 
    IsEditable="True" 
    IsTextSearchEnabled="False" 
    StaysOpenOnEdit="True">

    <MyControls:FilteredComboBox.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel VirtualizationMode="Recycling" />
        </ItemsPanelTemplate>
    </MyControls:FilteredComboBox.ItemsPanel>
</MyControls:FilteredComboBox>

Hier sind ein paar Dinge zu beachten. Sie werden feststellen, dass die FilterItem-Implementierung einen ToString() auf das Objekt anwendet. Das bedeutet, dass die Eigenschaft Ihres Objekts, die Sie anzeigen möchten, in Ihrer object.ToString()-Implementierung zurückgegeben werden sollte (oder bereits ein String ist). (oder bereits eine Zeichenkette sein) Mit anderen Worten etwa so:

public class Customer
{
    public string Name { get; set; }
    public string Address { get; set; }
    public string PhoneNumber { get; set; }

    public override string ToString()
    {
        return Name;
    }
}

Wenn dies nicht für Ihre Bedürfnisse funktioniert, nehme ich an, Sie könnten den Wert von DisplayMemberPath erhalten und Reflexion verwenden, um die Eigenschaft zu verwenden, aber das wäre langsamer, so dass ich nicht empfehlen würde, das zu tun, es sei denn notwendig.

Auch diese Implementierung hält den Benutzer NICHT davon ab, in den TextBox-Teil der ComboBox einzugeben, was immer er möchte. Wenn sie dort etwas Dummes eingeben, wird das SelectedItem auf NULL zurückgesetzt, also seien Sie darauf vorbereitet, das in Ihrem Code zu behandeln.

Auch wenn Sie viele Elemente haben, würde ich sehr empfehlen, die VirtualizingStackPanel wie mein Beispiel oben, wie es macht einen Unterschied in der Ladezeit

14voto

Jordi Punkte 1160

Basierend auf diese Antwort , fügte ich hinzu:

  • Die Möglichkeit, die Benutzereingabe auf die Werte zu beschränken, die in der InputSource mit OnlyValuesInList Eigentum.
  • Esc-Taste drücken, um Filter zu löschen
  • Handhabung der Pfeiltaste nach unten, um die ComboBox zu öffnen.
  • Mit der Rücktaste wird die Auswahl nicht gelöscht, sondern nur der Text gefiltert.
  • Versteckte Hilfsklassen und -methoden
  • Unnötige Methoden gestrichen
  • Hinzugefügt SelectionEffectivelyChanged Ereignis, das nur ausgelöst wird, wenn der Benutzer das Steuerelement verlässt oder die Eingabetaste drückt, wie bei der Filterung der SelectionChanged Ereignis der Standard-Combobox wird mehrmals ausgelöst.
  • Hinzugefügt EffectivelySelectedItem Eigenschaft, die sich nur ändert, wenn der Benutzer das Steuerelement verlässt oder die Eingabetaste drückt, wie bei der Filterung der SelectedItem Element aus der Standard-Combobox ändert sich mehrmals.

    public class FilterableComboBox : ComboBox { /// <summary> /// If true, on lost focus or enter key pressed, checks the text in the combobox. If the text is not present /// in the list, it leaves it blank. /// </summary> public bool OnlyValuesInList { get => (bool)GetValue(OnlyValuesInListProperty); set => SetValue(OnlyValuesInListProperty, value); } public static readonly DependencyProperty OnlyValuesInListProperty = DependencyProperty.Register(nameof(OnlyValuesInList), typeof(bool), typeof(FilterableComboBox));

    /// <summary>
    /// Selected item, changes only on lost focus or enter key pressed
    /// </summary>
    public object EffectivelySelectedItem {
        get => (bool)GetValue(EffectivelySelectedItemProperty);
        set => SetValue(EffectivelySelectedItemProperty, value);
    }
    public static readonly DependencyProperty EffectivelySelectedItemProperty =
        DependencyProperty.Register(nameof(EffectivelySelectedItem), typeof(object), typeof(FilterableComboBox));
    
    private string CurrentFilter = string.Empty;
    private bool TextBoxFreezed;
    protected TextBox EditableTextBox => GetTemplateChild("PART_EditableTextBox") as TextBox;
    private UserChange<bool> IsDropDownOpenUC;
    
    /// <summary>
    /// Triggers on lost focus or enter key pressed, if the selected item changed since the last time focus was lost or enter was pressed.
    /// </summary>
    public event Action<FilterableComboBox, object> SelectionEffectivelyChanged;
    
    public FilterableComboBox()
    {
        IsDropDownOpenUC = new UserChange<bool>(v => IsDropDownOpen = v);
        DropDownOpened += FilteredComboBox_DropDownOpened;
    
        IsEditable = true;
        IsTextSearchEnabled = true;
        StaysOpenOnEdit = true;
        IsReadOnly = false;
    
        Loaded += (s, e) => {
            if (EditableTextBox != null)
                new TextBoxBaseUserChangeTracker(EditableTextBox).UserTextChanged += FilteredComboBox_UserTextChange;
        };
    
        SelectionChanged += (_, __) => shouldTriggerSelectedItemChanged = true;
    
        SelectionEffectivelyChanged += (_, o) => EffectivelySelectedItem = o;
    }
    
    protected override void OnPreviewKeyDown(KeyEventArgs e)
    {
        base.OnPreviewKeyDown(e);
        if (e.Key == Key.Down && !IsDropDownOpen) {
            IsDropDownOpen = true;
            e.Handled = true;
        }
        else if (e.Key == Key.Escape) {
            ClearFilter();
            Text = "";
            IsDropDownOpen = true;
        }
        else if (e.Key == Key.Enter || e.Key == Key.Tab) {
            CheckSelectedItem();
            TriggerSelectedItemChanged();
        }
    }
    
    protected override void OnPreviewLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
    {
        base.OnPreviewLostKeyboardFocus(e);
        CheckSelectedItem();
        if ((e.OldFocus == this || e.OldFocus == EditableTextBox) && e.NewFocus != this && e.NewFocus != EditableTextBox)
            TriggerSelectedItemChanged();
    }
    
    private void CheckSelectedItem()
    {
        if (OnlyValuesInList)
            Text = SelectedItem?.ToString() ?? "";
    }
    
    private bool shouldTriggerSelectedItemChanged = false;
    private void TriggerSelectedItemChanged()
    {
        if (shouldTriggerSelectedItemChanged) {
            SelectionEffectivelyChanged?.Invoke(this, SelectedItem);
            shouldTriggerSelectedItemChanged = false;
        }
    }
    
    public void ClearFilter()
    {
        if (string.IsNullOrEmpty(CurrentFilter)) return;
        CurrentFilter = "";
        CollectionViewSource.GetDefaultView(ItemsSource).Refresh();
    }
    
    private void FilteredComboBox_DropDownOpened(object sender, EventArgs e)
    {
        if (IsDropDownOpenUC.IsUserChange)
            ClearFilter();
    }
    
    private void FilteredComboBox_UserTextChange(object sender, EventArgs e)
    {
        if (TextBoxFreezed) return;
        var tb = EditableTextBox;
        if (tb.SelectionStart + tb.SelectionLength == tb.Text.Length)
            CurrentFilter = tb.Text.Substring(0, tb.SelectionStart).ToLower();
        else
            CurrentFilter = tb.Text.ToLower();
        RefreshFilter();
    }
    
    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);
    }
    
    private void RefreshFilter()
    {
        if (ItemsSource == null) return;
    
        var view = CollectionViewSource.GetDefaultView(ItemsSource);
        FreezTextBoxState(() => {
            var isDropDownOpen = IsDropDownOpen;
            //always hide because showing it enables the user to pick with up and down keys, otherwise it's not working because of the glitch in view.Refresh()
            IsDropDownOpenUC.Set(false);
            view.Refresh();
    
            if (!string.IsNullOrEmpty(CurrentFilter) || isDropDownOpen)
                IsDropDownOpenUC.Set(true);
    
            if (SelectedItem == null) {
                foreach (var itm in ItemsSource)
                    if (itm.ToString() == Text) {
                        SelectedItem = itm;
                        break;
                    }
            }
        });
    }
    
    private void FreezTextBoxState(Action action)
    {
        TextBoxFreezed = true;
        var tb = EditableTextBox;
        var text = Text;
        var selStart = tb.SelectionStart;
        var selLen = tb.SelectionLength;
        action();
        Text = text;
        tb.SelectionStart = selStart;
        tb.SelectionLength = selLen;
        TextBoxFreezed = false;
    }
    
    private bool FilterItem(object value)
    {
        if (value == null) return false;
        if (CurrentFilter.Length == 0) return true;
    
        return value.ToString().ToLower().Contains(CurrentFilter);
    }
    
    private class TextBoxBaseUserChangeTracker
    {
        private bool IsTextInput { get; set; }
    
        public TextBoxBase TextBoxBase { get; set; }
        private List<Key> PressedKeys = new List<Key>();
        public event EventHandler UserTextChanged;
        private string LastText;
    
        public TextBoxBaseUserChangeTracker(TextBoxBase textBoxBase)
        {
            TextBoxBase = textBoxBase;
            LastText = TextBoxBase.ToString();
    
            textBoxBase.PreviewTextInput += (s, e) => {
                IsTextInput = true;
            };
    
            textBoxBase.TextChanged += (s, e) => {
                var isUserChange = PressedKeys.Count > 0 || IsTextInput || LastText == TextBoxBase.ToString();
                IsTextInput = false;
                LastText = TextBoxBase.ToString();
                if (isUserChange)
                    UserTextChanged?.Invoke(this, e);
            };
    
            textBoxBase.PreviewKeyDown += (s, e) => {
                switch (e.Key) {
                    case Key.Back:
                    case Key.Space:
                        if (!PressedKeys.Contains(e.Key))
                            PressedKeys.Add(e.Key);
                        break;
                }
                if (e.Key == Key.Back) {
                    var textBox = textBoxBase as TextBox;
                    if (textBox.SelectionStart > 0 && textBox.SelectionLength > 0 && (textBox.SelectionStart + textBox.SelectionLength) == textBox.Text.Length) {
                        textBox.SelectionStart--;
                        textBox.SelectionLength++;
                        e.Handled = true;
                        UserTextChanged?.Invoke(this, e);
                    }
                }
            };
    
            textBoxBase.PreviewKeyUp += (s, e) => {
                if (PressedKeys.Contains(e.Key))
                    PressedKeys.Remove(e.Key);
            };
    
            textBoxBase.LostFocus += (s, e) => {
                PressedKeys.Clear();
                IsTextInput = false;
            };
        }
    }
    
    private class UserChange<T>
    {
        private Action<T> action;
    
        public bool IsUserChange { get; private set; } = true;
    
        public UserChange(Action<T> action)
        {
            this.action = action;
        }
    
        public void Set(T val)
        {
            try {
                IsUserChange = false;
                action(val);
            }
            finally {
                IsUserChange = true;
            }
        }
    }

    }

6voto

YantingChen Punkte 668

Die Antwort von Kelly ist großartig. Allerdings gibt es einen kleinen Fehler, dass, wenn Sie ein Element in der Liste auswählen (Hervorhebung des Eingabetextes) und dann BackSpace drücken, wird der Eingabetext auf das ausgewählte Element zurückkehren und die SelectedItem-Eigenschaft der ComboBox ist immer noch das Element, das Sie zuvor ausgewählt.

Nachfolgend finden Sie den Code zur Behebung des Fehlers und zum Hinzufügen der Möglichkeit, das Element automatisch auszuwählen, wenn der Eingabetext mit ihm übereinstimmt.

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

2voto

Hrvoje Batrnek Punkte 462

Das ist meine Meinung dazu. Eine andere Herangehensweise, eine, die ich für mich selbst entwickelt habe und die ich anwende. Er funktioniert mit IsTextSearchEnabled="true". Ich habe es gerade erst fertiggestellt, daher kann es noch einige Fehler geben.

    public class TextBoxBaseUserChangeTracker
{
    private bool IsTextInput { get; set; }

    public TextBoxBase TextBox { get; set; }
    private List<Key> PressedKeys = new List<Key>();
    public event EventHandler UserTextChanged;
    private string LastText;

    public TextBoxBaseUserChangeTracker(TextBoxBase textBox)
    {
        TextBox = textBox;
        LastText = TextBox.ToString();

        textBox.PreviewTextInput += (s, e) =>
        {
            IsTextInput = true;
        };

        textBox.TextChanged += (s, e) =>
        {
            var isUserChange = PressedKeys.Count > 0 || IsTextInput || LastText == TextBox.ToString();
            IsTextInput = false;
            LastText = TextBox.ToString();
            if (isUserChange)
                UserTextChanged?.Invoke(this, e);
        };

        textBox.PreviewKeyDown += (s, e) =>
        {
            switch (e.Key)
            {
                case Key.Back:
                case Key.Space:
                case Key.Delete:
                    if (!PressedKeys.Contains(e.Key))
                        PressedKeys.Add(e.Key);
                    break;
            }
        };

        textBox.PreviewKeyUp += (s, e) =>
        {
            if (PressedKeys.Contains(e.Key))
                PressedKeys.Remove(e.Key);
        };

        textBox.LostFocus += (s, e) =>
        {
            PressedKeys.Clear();
            IsTextInput = false;
        };
    }
}

    public static class ExtensionMethods
{
    #region DependencyObject
    public static T FindParent<T>(this DependencyObject child) where T : DependencyObject
    {
        //get parent item
        DependencyObject parentObject = VisualTreeHelper.GetParent(child);

        //we've reached the end of the tree
        if (parentObject == null) return null;

        //check if the parent matches the type we're looking for
        T parent = parentObject as T;
        if (parent != null)
            return parent;
        else
            return parentObject.FindParent<T>();
    }
    #endregion

    #region TextBoxBase
    public static TextBoxBaseUserChangeTracker TrackUserChange(this TextBoxBase textBox)
    {
        return new TextBoxBaseUserChangeTracker(textBox);
    }
    #endregion
}

    public class UserChange<T>
{
    private Action<T> action;

    private bool isUserChange = true;
    public bool IsUserChange
    {
        get
        {
            return isUserChange;
        }
    }

    public UserChange(Action<T> action)
    {
        this.action = action;
    }

    public void Set(T val)
    {
        try
        {
            isUserChange = false;
            action(val);
        }
        finally
        {
            isUserChange = true;
        }
    }
}

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

    private string CurrentFilter = string.Empty;
    private bool TextBoxFreezed;
    protected TextBox EditableTextBox => GetTemplateChild("PART_EditableTextBox") as TextBox;
    private UserChange<bool> IsDropDownOpenUC;

    public FilteredComboBox()
    {
        IsDropDownOpenUC = new UserChange<bool>(v => IsDropDownOpen = v);
        DropDownOpened += FilteredComboBox_DropDownOpened;

        Loaded += (s, e) =>
        {
            if (EditableTextBox != null)
            {
                EditableTextBox.TrackUserChange().UserTextChanged += FilteredComboBox_UserTextChange;
            }
        };
    }

    public void ClearFilter()
    {
        if (string.IsNullOrEmpty(CurrentFilter)) return;
        CurrentFilter = "";
        CollectionViewSource.GetDefaultView(ItemsSource).Refresh();
    }

    private void FilteredComboBox_DropDownOpened(object sender, EventArgs e)
    {
        //if user opens the drop down show all items
        if (IsDropDownOpenUC.IsUserChange)
            ClearFilter();
    }

    private void FilteredComboBox_UserTextChange(object sender, EventArgs e)
    {
        if (TextBoxFreezed) return;
        var tb = EditableTextBox;
        if (tb.SelectionStart + tb.SelectionLength == tb.Text.Length)
            CurrentFilter = tb.Text.Substring(0, tb.SelectionStart).ToLower();
        else
            CurrentFilter = tb.Text.ToLower();
        RefreshFilter();
    }

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

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

        var view = CollectionViewSource.GetDefaultView(ItemsSource);
        FreezTextBoxState(() =>
        {
            var isDropDownOpen = IsDropDownOpen;
            //always hide because showing it enables the user to pick with up and down keys, otherwise it's not working because of the glitch in view.Refresh()
            IsDropDownOpenUC.Set(false);
            view.Refresh();

            if (!string.IsNullOrEmpty(CurrentFilter) || isDropDownOpen)
                IsDropDownOpenUC.Set(true);

            if (SelectedItem == null)
            {
                foreach (var itm in ItemsSource)
                {
                    if (itm.ToString() == Text)
                    {
                        SelectedItem = itm;
                        break;
                    }
                }
            }
        });
    }

    private void FreezTextBoxState(Action action)
    {
        TextBoxFreezed = true;
        var tb = EditableTextBox;
        var text = Text;
        var selStart = tb.SelectionStart;
        var selLen = tb.SelectionLength;
        action();
        Text = text;
        tb.SelectionStart = selStart;
        tb.SelectionLength = selLen;
        TextBoxFreezed = false;
    }

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

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

Xaml:

        <local:FilteredComboBox ItemsSource="{Binding List}" IsEditable="True" IsTextSearchEnabled="true" StaysOpenOnEdit="True" x:Name="cmItems" SelectionChanged="CmItems_SelectionChanged">

    </local:FilteredComboBox>

1voto

Aviad P. Punkte 30713

Es klingt wie das, was Sie wirklich suchen, ist etwas ähnlich wie eine Auto-Vervollständigung Textbox, die Vervollständigung Vorschläge in einem Popup ähnlich wie eine Combobox Popup bietet.

Vielleicht finden Sie diesen CodeProject-Artikel nützlich:

Eine wiederverwendbare WPF Autocomplete TextBox

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X