【问题标题】:Issue with WPF custom control (Multi-Select Combobox)WPF 自定义控件问题(多选组合框)
【发布时间】:2011-03-15 13:23:47
【问题描述】:

在代码项目中,我发现以下内容: http://www.codeproject.com/KB/WPF/MultiComboBox.aspx

我已将以下内容集成到示例应用程序中,它似乎运行良好。我现在唯一的问题是,如果我在控件中键入内容,我希望以与普通组合框或列表框相同的方式转到以这些字母开头的项目。

我已尝试添加KeyboardNavigation.DirectionalNavigation="Contained"TextSearch.TextPath="City" 以及IsTextSearchEnabled="True"

这些似乎都没有帮助。关于如何使用此控件实现文本搜索功能的任何想法?

【问题讨论】:

  • 如果只能在后面的代码中完成,那么可以。任何一种语言都可以,如有必要,我可以转换。如果可以纯粹在 XAML 中完成,那就更好了。

标签: c# .net wpf xaml user-controls


【解决方案1】:

作者确认该控件是为模仿ComboBox 而构建的,但事实并非如此:您应该为自动选择实现自己的自定义逻辑。

编辑(也就是比手指插入眼睛更好)

参考原代码: 1) 在 Generic.xaml 中搜索 MultiSelectComboBoxReadOnlyTemplate,然后查找 ScrollViewer 标签:将其命名为“PART_Scroller”。

2) 打开 MultiComboBox.cs 模块,然后找到 OnKeyDown 函数。修改如下:

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

你应该做的关键分析比矿山更好,但道路相当阳光明媚。 注意:我没有尝试太多测试,我想应该没问题,至少给你一个帮助。 干杯 马里奥

EDIT2:这里是如何在一秒钟内跟踪按下的键。 1) 修改如下:

    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) 将以下内容添加到同一类中:

    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;

希望对您有所帮助。 干杯 马里奥

【讨论】:

  • 这正是我所坚持的......因此,问题
  • 让我很好理解:一旦列表下拉,您会按一个键,以便列表滚动到最近的以该字母开头的项目?或者您想要一个更时髦的组合,只过滤(然后显示)包含该字母的项目?
  • 按一个键并将列表滚动到最近以该字母开头的位置
  • 这很好,谢谢!这是否可以搜索多个字符的长度?由于事件是 OnKeyDown,我不太确定最好的实现是什么,但有什么想法吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-04
  • 1970-01-01
  • 1970-01-01
  • 2011-10-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多