0

I'm trying to implement a custom combobox control that I found here :

https://stackoverflow.com/a/48559118

(I cannot post a comment because of my low reputation)

This custom combobox is designed to filter items in a combobox based on text input.

The solution mostly works except for one thing. When a user types a text in the combobox, then select an entry it is not possible anymore to do a SelectedItem = xyz from codebehind (same issue with binding, wanted to make a simple sample to reproduce the issue).

Sample Code :

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>

I think that the issue might be related to the fact that the list doesn't contain anymore the item because it has been filtered out ?!

I struggle to find a way to fix this in the custom control.

Edit, custom control code :

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());
        }
    }
}
Coloris
  • 35
  • 8
  • Sounds like the issue is in the FilteredComboBox control code. Can you post the custom combobox code code as well? ... nm, I see the custom code in the link provided. Before digging into that code, have you changed anything or is it exact copy paste? – Michael Puckett II Apr 09 '18 at 17:07
  • it is a exact copy and paste ! I will update my post with the custom control code, thanks ! – Coloris Apr 09 '18 at 17:13
  • You're filtering the item out what it can select from. Don't make the selecteditem something that isn't in the filtered listcollectionview. – Andy Apr 09 '18 at 18:56
  • You are right Andy but the thing is that I need to be able to select an item that was already in the list before the user selection (in fact my requirement is to be able to select an item, no matter if the combobox has been used before or not) – Coloris Apr 09 '18 at 19:05

0 Answers0