WPF可编辑组合框缓慢打字 [英] WPF editable combobox slow typing

查看:79
本文介绍了WPF可编辑组合框缓慢打字的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在xaml中定义了一个这样的组合框:



I have a combobox defined in xaml like this :

<ComboBox x:Name="CustomerComboBox" IsEditable="True" ItemsSource="{Binding Relations.View}" DisplayMemberPath="Model.sname" />





如果我是clic k在可编辑的组合中,当绑定到位(MVVM)给它焦点,然后我按住任意键,我认为组合将很快填充该键,但它不是。如果我删除displaymemberpath然后执行相同操作,那么我有预期的行为。当然我真的需要绑定。



在系统启动期间完成填充作为模型一部分的viewsource的底层数据库调用。这个电话实际上只进行过一次。性能问题仅归因于组合框本身。



我无法理解性能损失的来源。有没有办法绕过这个问题?



If I click in the editable combo while the binding is in place (MVVM) to give it focus, and I then press and hold any key, I assume the combo will be filled with that key rather quickly, but it isn''t. If I remove the displaymemberpath and then do the same, then I have the expected behavior. Of course I really need the binding.

The underlying database call to fill the viewsource that is part of the model, is done during system startup. This call is in fact done only once. The performance problem is only due to the combobox itself.

I cannot understand where this performance penalty is coming from. Is there any way to bypass this problem ?

推荐答案

下面的代码解决了这个问题。

标准组合框浪费时间处理每个项目多次取决于事件。例如,每次按下一个键。另见我之前发表的评论。



Following code solves the issue.
The standard combobox wastes time processing each and every item multiple times depending on the event. For instance each and every time a key is pressed. See also my comment posted earlier.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Reflection;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Windows.Controls.Primitives;
using System.Collections;

namespace ICeTechControlLibrary
{
    public class FastEditComboBox : ComboBox
    {
        //PARTS
        private TextBox _TextBoxPart = null;

        //DEPENDENCY PROPERTIES
        public static readonly DependencyProperty TextProperty
            = DependencyProperty.Register("Text", typeof(string), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.Journal | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(FastEditComboBox.OnTextChanged)));

        private List<string> _CompletionStrings = new List<string>();
        private int _textBoxSelectionStart;
        private bool _updatingText;
        private bool _updatingSelectedItem;
        private static Dictionary<textbox,> _TextBoxDictionary = new Dictionary<textbox,fasteditcombobox>();

        static FastEditComboBox()
        {
            EventManager.RegisterClassHandler(typeof(TextBox), TextBox.TextChangedEvent, new TextChangedEventHandler(FastEditComboBox.OnTextChanged));
            EventManager.RegisterClassHandler(typeof(TextBox), TextBox.SelectionChangedEvent, new RoutedEventHandler(FastEditComboBox.OnSelectionChanged));
        }

        public string Text
        {
            get
            {
                return (string)base.GetValue(TextProperty);
            }
            set
            {
                base.SetValue(TextProperty, value);
            }
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            _TextBoxPart = base.GetTemplateChild("PART_EditableTextBox") as TextBox;
            if (!_TextBoxDictionary.ContainsKey(_TextBoxPart)) _TextBoxDictionary.Add(_TextBoxPart, this);
        }

        private void OnTextBoxSelectionChanged(object sender, RoutedEventArgs e)
        {
            this._textBoxSelectionStart = this._TextBoxPart.SelectionStart;
        }

        private void OnTextBoxTextChanged(object sender, TextChangedEventArgs e)
        {
            if (IsEditable)
            {
                TextUpdated(_TextBoxPart.Text, true);
            }
        }

        private void TextUpdated(string newText, bool textBoxUpdated)
        {
            if (!_updatingText && !_updatingSelectedItem)
            {
                try
                {
                    _updatingText = true;
                    if (base.IsTextSearchEnabled)
                    {
                        int num = FindMatchingPrefix(newText);
                        if (num >= 0)
                        {
                            if (textBoxUpdated)
                            {
                                int selectionStart = this._TextBoxPart.SelectionStart;
                                if ((selectionStart == newText.Length) && (selectionStart > this._textBoxSelectionStart))
                                {
                                    string primaryTextFromItem = _CompletionStrings[num];
                                    this._TextBoxPart.Text = primaryTextFromItem;
                                    this._TextBoxPart.SelectionStart = newText.Length;
                                    this._TextBoxPart.SelectionLength = primaryTextFromItem.Length - newText.Length;
                                    newText = primaryTextFromItem;
                                }
                            }
                            else
                            {
                                string b = _CompletionStrings[num];
                                if (!string.Equals(newText, b, StringComparison.CurrentCulture))
                                {
                                    num = -1;
                                }
                            }
                        }
                        if (num != base.SelectedIndex)
                        {
                            SelectedIndex = num;
                        }
                    }
                    if (textBoxUpdated)
                    {
                        Text = newText;
                    }
                    else if (_TextBoxPart != null)
                    {
                        _TextBoxPart.Text = newText;
                    }
                }
                finally
                {
                    _updatingText = false;
                }
            }
        }

        internal void SelectedItemUpdated()
        {
            try
            {
                this._updatingSelectedItem = true;
                if (!this._updatingText)
                {
                    string primaryTextFromItem = GetPrimaryTextFromItem(SelectedItem);
                    Text = primaryTextFromItem;
                }
                this.Update();
            }
            finally
            {
                this._updatingSelectedItem = false;
            }
        }

        private void Update()
        {
            if (this.IsEditable)
            {
                this.UpdateEditableTextBox();
            }
            else
            {
                //this.UpdateSelectionBoxItem();
            }
        }

        private void UpdateEditableTextBox()
        {
            if (!_updatingText)
            {
                try
                {
                    this._updatingText = true;
                    string text = this.Text;
                    if ((this._TextBoxPart != null) && (this._TextBoxPart.Text != text))
                    {
                        this._TextBoxPart.Text = text;
                        this._TextBoxPart.SelectAll();
                    }
                }
                finally
                {
                    this._updatingText = false;
                }
            }
        }

        protected override void OnSelectionChanged(SelectionChangedEventArgs e)
        {
            base.RaiseEvent(e);
            this.SelectedItemUpdated();
            if (this.IsDropDownOpen)
            {
                object Item = SelectedItem;
                if (Item != null)
                {
                    base.OnSelectionChanged(e);
                }
                //object internalSelectedItem = base.InternalSelectedItem;
                //if (internalSelectedItem != null)
                //{
                //    base.NavigateToItem(internalSelectedItem, ItemsControl.ItemNavigateArgs.Empty);
                //}
            }
        }

        int FindMatchingPrefix(string s)
        {
            int index = _CompletionStrings.BinarySearch(s, StringComparer.OrdinalIgnoreCase);
            if (index >= 0) return index;
            index = ~index;
            string p = _CompletionStrings[index];
            if (p.StartsWith(s, StringComparison.CurrentCultureIgnoreCase)) return index;
            return -1;
        }

        protected override void OnDisplayMemberPathChanged(string oldDisplayMemberPath, string newDisplayMemberPath)
        {
            FillCompletionStrings();
        }

        protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            base.OnItemsChanged(e);
            switch (e.Action)
            {
                case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
                    AddCompletionStrings(e.NewItems);
                    break;
                case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
                    RemoveCompletionStrings(e.OldItems);
                    break;
                case System.Collections.Specialized.NotifyCollectionChangedAction.Reset:
                    FillCompletionStrings();
                    break;
            }
        }

        private void FillCompletionStrings()
        {
            _CompletionStrings.Clear();
            AddCompletionStrings(Items);
        }

        private void RemoveCompletionStrings(IList items)
        {
            foreach (object o in items)
            {
                RemoveCompletionStringForItem(o);
            }
        }

        private void AddCompletionStrings(IList items)
        {
            foreach (object o in items)
            {
                AddCompletionStringForItem(o);
            }
        }

        private void AddCompletionStringForItem(object item)
        {
            Binding binding = new Binding(DisplayMemberPath);
            TextBlock tb = new TextBlock();
            tb.DataContext = item;
            tb.SetBinding(TextBlock.TextProperty, binding);
            string s = tb.Text;
            int index = _CompletionStrings.BinarySearch(s, StringComparer.OrdinalIgnoreCase);
            if (index < 0)
            {
                _CompletionStrings.Insert(~index, s);
            }
            else
            {
                _CompletionStrings.Insert(index, s);
            }
        }

        private string GetPrimaryTextFromItem(object item)
        {
            Binding binding = new Binding(DisplayMemberPath);
            TextBlock tb = new TextBlock();
            tb.DataContext = item;
            tb.SetBinding(TextBlock.TextProperty, binding);
            string s = tb.Text;
            return s;
        }

        private void RemoveCompletionStringForItem(object item)
        {
            Binding binding = new Binding(DisplayMemberPath);
            TextBlock tb = new TextBlock();
            tb.DataContext = item;
            tb.SetBinding(TextBlock.TextProperty, binding);
            string s = tb.Text;
            int index = _CompletionStrings.BinarySearch(s, StringComparer.OrdinalIgnoreCase);
            if (index >= 0) _CompletionStrings.RemoveAt(index);
        }

        private static void OnTextChanged(object sender, TextChangedEventArgs e)
        {
            TextBox tb = e.Source as TextBox;
            if (tb.Name == "PART_EditableTextBox")
            {
                if (_TextBoxDictionary.ContainsKey(tb))
                {
                    FastEditComboBox combo = _TextBoxDictionary[tb];
                    combo.OnTextBoxTextChanged(sender, e);
                    e.Handled = true;
                }
            }
        }

        private static void OnSelectionChanged(object sender, RoutedEventArgs e)
        {
            TextBox tb = e.Source as TextBox;
            if (tb.Name == "PART_EditableTextBox")
            {
                if (_TextBoxDictionary.ContainsKey(tb))
                {
                    FastEditComboBox combo = _TextBoxDictionary[tb];
                    combo.OnTextBoxSelectionChanged(sender, e);
                    e.Handled = true;
                }
            }
        }

        private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            FastEditComboBox actb = (FastEditComboBox)d;
            actb.TextUpdated((string)e.NewValue, false);
        }
    }
}


这篇关于WPF可编辑组合框缓慢打字的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆