performance - WPF editable combobox slow typing -
i have wpf combobox :
<combobox x:name="customercombobox" iseditable="true" itemssource="{binding relations.view}" displaymemberpath="model.sname" />
if click in editable combo while binding in place (mvvm) give focus, , press , hold key, assume combo filled key rather quickly, isn't. if remove displaymemberpath , same, have expected behavior. of course need binding.
the performance penalty shows when combo has lot of elements mine has 6000.
i cannot understand performance penalty coming from. there way bypass problem ?
below code solves issues creating specialised combobox caches binding results. created looking @ orginal source code of combobox , itemscontrol using .net reflector.
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 { { return (string)base.getvalue(textproperty); } set { base.setvalue(textproperty, value); } } public override void onapplytemplate() { base.onapplytemplate(); _textboxpart = base.gettemplatechild("part_editabletextbox") 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; } } { _updatingtext = false; } } } internal void selecteditemupdated() { try { this._updatingselecteditem = true; if (!this._updatingtext) { string primarytextfromitem = getprimarytextfromitem(selecteditem); text = primarytextfromitem; } this.update(); } { 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(); } } { 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 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 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); } } }
selecting first element clears selection implementation. still bugs here
Comments
Post a Comment