简体   繁体   中英

Issue with WPF custom control (Multi-Select Combobox)

On code project I found the following: http://www.codeproject.com/KB/WPF/MultiComboBox.aspx

I have integrated the following into a sample application and it seems to be working well. The only issue I have right now is that if I type in the control I would like to be taken to the items that start with those letters the same way a normal combobox or listbox functions.

I have tried adding KeyboardNavigation.DirectionalNavigation="Contained" and TextSearch.TextPath="City" as well as IsTextSearchEnabled="True" .

None of these seem to be helping. Any thoughts on how to implement text search functionality using this control?

The author confirm that the control is build to mimic a ComboBox , but it isn't: you should implement your own custom logic to the automatic selection.

EDIT (aka even better than a finger in the eye)

With reference to the original code: 1) In the Generic.xaml search the MultiSelectComboBoxReadOnlyTemplate , then look for the ScrollViewer tag: name it as "PART_Scroller".

2) Open the MultiComboBox.cs module then find the OnKeyDown function. Modify as follows:

    protected override void OnKeyDown(KeyEventArgs e)
    {
        if (e.Key == System.Windows.Input.Key.Enter)
        {
            IsDropDownOpen = !IsDropDownOpen;
            e.Handled = true;
        }
        else if (IsDropDownOpen)
        {
            if (e.Key>=Key.A && e.Key<= Key.Z) //make it better!
            {
                var ch = (char)((int)(e.Key-Key.A) + 0x41); //awful!!!
                for (int i = 0, count = this.Items.Count; i < count; i++)
                {
                    var text = string.Format("{0}", this.Items[i]);
                    if (text.StartsWith(new string(ch, 1)))
                    {
                        ListBoxItem listBoxItem = (ListBoxItem)this.ItemContainerGenerator.ContainerFromIndex(i);
                        var scroller = (ScrollViewer)this.GetTemplateChild("PART_Scroller"); //move out in OnApplyTemplate
                        scroller.ScrollToVerticalOffset(i);
                        this.ScrollIntoView(listBoxItem);
                        break;
                    }
                }

            }
        }
        else
            base.OnKeyDown(e);
    }

You should make the key analysis better than the mine, but the road is pretty sunny. NOTE: I didn't tried so much to test, I guess should be OK, at least to give you an help. Cheers Mario

EDIT2: here is how to keeping track of the key pressed within one second. 1) Modify as follows:

    protected override void OnKeyDown(KeyEventArgs e)
    {
        if (e.Key == System.Windows.Input.Key.Enter)
        {
            IsDropDownOpen = !IsDropDownOpen;
            e.Handled = true;
        }
        else if (IsDropDownOpen)
        {
            if (e.Key>=Key.A && e.Key<= Key.Z) //make it better!
            {
                var ch = (char)((int)(e.Key-Key.A) + 0x41); //awful!!!
                this._textSought += ch;
                this._timer.Stop();
                this._timer.Start();

                for (int i = 0, count = this.Items.Count; i < count; i++)
                {
                    var text = string.Format("{0}", this.Items[i]);
                    if (text.StartsWith(this._textSought, StringComparison.InvariantCultureIgnoreCase))
                    {
                        ListBoxItem listBoxItem = (ListBoxItem)this.ItemContainerGenerator.ContainerFromIndex(i);
                        var scroller = (ScrollViewer)this.GetTemplateChild("PART_Scroller"); //move out in OnApplyTemplate
                        scroller.ScrollToVerticalOffset(i);
                        this.ScrollIntoView(listBoxItem);
                        break;
                    }
                }

            }
        }
        else
            base.OnKeyDown(e);
    }

2) add the following to the same class:

    public MultiComboBox()
    {
        this.Loaded += new RoutedEventHandler(MultiComboBox_Loaded);
        this.Unloaded += new RoutedEventHandler(MultiComboBox_Unloaded);
    }

    void MultiComboBox_Loaded(object sender, RoutedEventArgs e)
    {
        this._timer = new DispatcherTimer();
        this._timer.Interval = TimeSpan.FromMilliseconds(1000);
        this._timer.Tick += new EventHandler(_timer_Tick);
    }

    void MultiComboBox_Unloaded(object sender, RoutedEventArgs e)
    {
        if (this._timer != null)
        {
            this._timer.Stop();
            this._timer = null;
        }
    }

    void _timer_Tick(object sender, EventArgs e)
    {
        this._timer.Stop();
        this._textSought = string.Empty;
    }

    private DispatcherTimer _timer;
    private string _textSought = string.Empty;

Hope it helps. Cheers Mario

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM