c# - How can I run code inside a Converter on a separate thread so that the UI does not freeze? -
i have wpf converter slow (computations, online fetching, etc.). how can convert asynchronously ui doesn't freeze up? found this, solution place converter code in property - http://social.msdn.microsoft.com/forums/pl-pl/wpf/thread/50d288a2-eadc-4ed6-a9d3-6e249036cb71 - rather not do.
below example demonstrates issue. here dropdown freeze until sleep elapses.
namespace testasync { using system; using system.collections.generic; using system.threading; using system.windows; using system.windows.data; using system.windows.threading; /// <summary> /// interaction logic mainwindow.xaml /// </summary> public partial class mainwindow : window { public mainwindow() { initializecomponent(); mynumbers = new dictionary<string, int> { { "uno", 1 }, { "dos", 2 }, { "tres", 3 } }; this.datacontext = this; } public dictionary<string, int> mynumbers { { return (dictionary<string, int>)getvalue(mynumbersproperty); } set { setvalue(mynumbersproperty, value); } } public static readonly dependencyproperty mynumbersproperty = dependencyproperty.register("mynumbers", typeof(dictionary<string, int>), typeof(mainwindow), new uipropertymetadata(null)); public string mynumber { { return (string)getvalue(mynumberproperty); } set { setvalue(mynumberproperty, value); } } public static readonly dependencyproperty mynumberproperty = dependencyproperty.register( "mynumber", typeof(string), typeof(mainwindow), new uipropertymetadata("uno")); } public class asyncconverter : imultivalueconverter { public object convert(object[] values, type targettype, object parameter, system.globalization.cultureinfo culture) { object result = null; if (values[0] string && values[1] idictionary<string, int>) { doasync( () => { thread.sleep(2000); // simulate long task var number = (string)(values[0]); var numbers = (idictionary<string, int>)(values[1]); result = numbers[number]; result = result.tostring(); }); } return result; } private void doasync(action action) { var frame = new dispatcherframe(); new thread((threadstart)(() => { action(); frame.continue = false; })).start(); dispatcher.pushframe(frame); } public object[] convertback(object value, type[] targettype, object parameter, system.globalization.cultureinfo culture) { throw new notsupportedexception(); } }
and xaml:
<window x:class="testasync.mainwindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:testasync" title="mainwindow" height="200" width="200"> <window.resources> <local:asyncconverter x:key="asyncconverter"/> </window.resources> <dockpanel> <combobox dockpanel.dock="top" selecteditem="{binding mynumber, isasync=true}" itemssource="{binding mynumbers.keys, isasync=true}"/> <textblock datacontext="{binding isasync=true}" fontsize="50" fontweight="bold" horizontalalignment="center" verticalalignment="center"> <textblock.text> <multibinding converter="{staticresource asyncconverter}"> <binding path="mynumber" isasync="true"/> <binding path="mynumbers" isasync="true"/> </multibinding> </textblock.text> </textblock> </dockpanel> </window>
note bindings isasync="true", doesn't help.
the combobox stuck 2000 ms.
i know said don't want invoke translation property setter, submit cleaner approach ivalueconverter
/imultivalueconverter
.
ultimately, want set value of selected number combobox, , return immediately. want defer updating displayed/translated value until translation process complete.
i think clearer model data such translated value property gets updated asynchronous process.
<combobox selecteditem="{binding selectednumber, mode=onewaytosource}" itemssource="{binding mynumbers.keys}"/> <textblock text="{binding mynumbervalue}" />
public partial class mainwindow : window, inotifypropertychanged { public mainwindow() { initializecomponent(); mynumbers = new dictionary<string, int> { { "uno", 1 }, { "dos", 2 }, { "tres", 3 } }; datacontext = this; } public idictionary<string, int> mynumbers { get; set; } string _selectednumber; public string selectednumber { { return _selectednumber; } set { _selectednumber = value; notify("selectednumber"); updatemynumbervalue(); } } int _mynumbervalue; public int mynumbervalue { { return _mynumbervalue; } set { _mynumbervalue = value; notify("mynumbervalue"); } } void updatemynumbervalue() { var key = selectednumber; if (key == null || !mynumbers.containskey(key)) return; new thread(() => { thread.sleep(3000); mynumbervalue = mynumbers[key]; }).start(); } public event propertychangedeventhandler propertychanged; void notify(string property) { var handler = propertychanged; if(handler != null) handler(this, new propertychangedeventargs(property)); } }
Comments
Post a Comment