WPF可编辑组合框慢速键入
我有一个WPF组合框,如下所示:WPF可编辑组合框慢速键入,wpf,performance,combobox,Wpf,Performance,Combobox,我有一个WPF组合框,如下所示: 如果我在绑定到位(MVVM)时单击可编辑组合以使其具有焦点,然后按住任意键,我假设组合将很快被该键填充,但事实并非如此。 如果我删除displaymemberpath,然后执行相同的操作,那么我就有了预期的行为。当然我真的需要装订 只有当组合有很多元素时,性能惩罚才会显示。我的元素有6000个 我不明白这场比赛的点球是从哪里来的。有没有办法绕过这个问题?下面的代码通过创建一个专门的组合框来解决问题,该组合框基本上缓存了所有绑定结果。我通过使用.NET refl
如果我在绑定到位(MVVM)时单击可编辑组合以使其具有焦点,然后按住任意键,我假设组合将很快被该键填充,但事实并非如此。
如果我删除displaymemberpath,然后执行相同的操作,那么我就有了预期的行为。当然我真的需要装订
只有当组合有很多元素时,性能惩罚才会显示。我的元素有6000个
我不明白这场比赛的点球是从哪里来的。有没有办法绕过这个问题?下面的代码通过创建一个专门的组合框来解决问题,该组合框基本上缓存了所有绑定结果。我通过使用.NET reflector查看combobox和itemscontrol的原始源代码创建了它
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, FastEditComboBox> _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);
}
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Data;
使用System.Windows.Documents;
使用System.Windows.Input;
使用System.Windows.Media;
使用System.Windows.Media.Imaging;
使用System.Windows.Navigation;
使用System.Windows.Shapes;
运用系统反思;
使用系统组件模型;
使用System.Collections.ObjectModel;
使用System.Windows.Controls.Primitives;
使用系统集合;
命名空间ICeTechControlLibrary
{
公共类FastEditComboBox:ComboBox
{
//零件
私有文本框_TextBoxPart=null;
//依赖属性
公共静态只读DependencyProperty TextProperty
=DependencyProperty.Register(“Text”、typeof(string)、typeof(AutoCompleteTextBox)、new FrameworkPropertyMetadata(string.Empty、FrameworkPropertyMetadataOptions.Journal | FrameworkPropertyMetadataOptions.Bindstwoway默认情况下,new PropertyChangedCallback(FastEditComboBox.OnTextChanged));
私有列表_CompletionStrings=新列表();
专用int_文本框选择启动;
私有bool\u更新文本;
私有bool\u更新selecteditem;
私有静态字典_TextBoxDictionary=新字典();
静态FastEditComboBox()
{
RegisterClassHandler(typeof(TextBox)、TextBox.TextChangedEvent、newtextchangedeventhandler(fastedicombobox.OnTextChanged));
EventManager.RegisterClassHandler(typeof(TextBox)、TextBox.SelectionChangedEvent、new RoutedEventHandler(fastedComboBox.OnSelectionChanged));
}
公共字符串文本
{
得到
{
返回(字符串)base.GetValue(TextProperty);
}
设置
{
base.SetValue(TextProperty,value);
}
}
应用程序模板()上的公共重写无效
{
base.OnApplyTemplate();
_TextBoxPart=base.GetTemplateChild(“PART\u EditableTextBox”)作为文本框;
如果(!\u TextBoxDictionary.ContainsKey(\u TextBoxPart))\u TextBoxDictionary.Add(\u TextBoxPart,this);
}
private void OnTextBoxSelectionChanged(对象发送方,路由目标)
{
this.\u textBoxSelectionStart=this.\u TextBoxPart.SelectionStart;
}
私有void OnTextBoxTextChanged(对象发送方,textchangedventargs e)
{
如果(可编辑)
{
TextUpdated(_TextBoxPart.Text,true);
}
}
私有无效文本更新(字符串newText,bool textBoxUpdated)
{
if(!\u updateText&!\u updateingselecteditem)
{
尝试
{
_updateText=true;
if(base.IsTextSearchEnabled)
{
int num=FindMatchingPrefix(新文本);
如果(num>=0)
{
如果(TextBoxUpdate)
{
int-selectionStart=这个;
如果((selectionStart==newText.Length)和&(selectionStart>this.\u文本框selectionStart))
{
字符串primaryTextFromItem=_CompletionStrings[num];
此._TextBoxPart.Text=primaryTextFromItem;
这是._TextBoxPart.SelectionStart=newText.Length;
此.u TextBoxPart.SelectionLength=primaryTextFromItem.Length-newText.Length;
newText=primaryTextFromItem;
}
}
其他的
{
字符串b=_CompletionStrings[num];
如果(!string.Equals(newText,b,StringComparison.CurrentCulture))
{
num=-1;
}
}
}
if(num!=base.SelectedIndex)
{
SelectedIndex=num;
}
}
如果(TextBoxUpdate)
{
文本=新文本;
}
else if(_TextBoxPart!=null)
{
_Text=newText;
}
}
最后
{
_updateText=false;
}
}
}
内部void SelectedItemUpdated()
{
尝试
{
这是.\u updatenselecteditem=true;
如果(!this.\u updateingtext)
{
字符串primaryTextFromItem=GetPrimaryTextFromItem(SelectedItem);