c# - Race condition with converters? -


i have wpf form has quite few dynamically created controls e.g. comboboxes.

on each combobox have few converters handle business logic. 1 of converters auto-populates n/a , disabled based on other input on form. however, should allowed auto-populated (the user should not able select this).

to accomplish this, have converter on itemssource of combobox filters out n/a option if combobox enabled, otherwise include can populated needed. have converter selecteditem auto-populate n/a answer.

however, there seems race condition in converters not fire in same order consistently, resulting in blank answers (the converter auto-populate selecteditem running before itemssource converter running add answer).

is there anyway ensure converters execute in same manner? creating bindings/converters in code-behind (since controls created dynamically) if makes difference.

edit: adding in code per request (however question more of general question). here code behind defining bindings/converters (i have template of each control in xaml , cloning here well):

            //filter out answeroptions (n/a, yes, no) based on other questions         multibinding itemssourcebinding = new multibinding();         itemssourcebinding.bindings.add(new binding("parentform.baselinequestionsproperty.imageadequacyproperty.singleanswer") { source = });         itemssourcebinding.bindings.add(new binding(".") { source = containerbase });         itemssourcebinding.bindings.add(new binding("parentform.baselinequestionsproperty.missingtoptionproperty.isselected") { source = });         itemssourcebinding.bindings.add(new binding("parentform.baselinequestionsproperty.missingloptionproperty.isselected") { source = });         itemssourcebinding.bindings.add(new binding("answeroptions") { source = containerbase });         itemssourcebinding.converter = new endplateanswerfilterconverter();         bindingoperations.setbinding(combobox, combobox.itemssourceproperty, itemssourcebinding);          //binding auto-populate answers based on image adequacy answer         multibinding singleanswerbinding = new multibinding();         singleanswerbinding.bindings.add(new binding("parentform.baselinequestionsproperty.imageadequacyproperty.singleanswer") { source = });         singleanswerbinding.bindings.add(new binding(".") { source = containerbase });         singleanswerbinding.bindings.add(new binding("parentform.baselinequestionsproperty.missingtcoptionproperty.isselected") { source = });         singleanswerbinding.bindings.add(new binding("parentform.baselinequestionsproperty.missingloptionproperty.isselected") { source = });         singleanswerbinding.converter = new endplatenotreadabletoanswerconverter();         bindingoperations.setbinding(containerbase, containerbase.singleanswerproperty, singleanswerbinding); 

here converters:

itemssource converter filter out answers:

    public class endplateanswerfilterconverter : imultivalueconverter {     public object convert(object[] values, system.type targettype, object parameter, system.globalization.cultureinfo culture)     {         if (values[0] answer && values[1] containerbase && values[2] bool && values[3] bool && values[4] observablecollection<answer> /*targettype == typeof(visibility)*/)         {             observablecollection<answer> itemssource = new observablecollection<answer>();              var answeroptions = (observablecollection<answer>)values[4];             var imageadequacyanswer = (answer)values[0];             var containerbase = (containerbase)values[1];             var missingtoptionselected = (bool)values[2];             var missingloptionselected = (bool)values[3];              //loop through answeroptions             foreach (var ans in answeroptions)             {                 //add n/a option if nr/missing images                 if (ans.value == ((int)yesnoanswers.notapplicable).tostring() &&                     (imageadequacyanswer.value == ((int)imageadequacyanswers.notreadable).tostring() ||                     (missingtoptionselected && containerbase.name.contains("_t")) ||                     (missingloptionselected && containerbase.name.contains("_l"))))                 {                     itemssource.add(ans);                 }                 //add yes/no otherwise                 else if (ans.value != ((int)yesnoanswers.notapplicable).tostring() &&                     !(imageadequacyanswer.value == ((int)imageadequacyanswers.notreadable).tostring() ||                     (missingtoptionselected && containerbase.name.contains("_t")) ||                     (missingloptionselected && containerbase.name.contains("_l"))))                 {                     itemssource.add(ans);                 }             }              return itemssource;         }         else         {             return null;         }     } 

converter auto-populate combobox (containerbase custom user control encapsulates combobox other properties well):

    public class endplatenotreadabletoanswerconverter : imultivalueconverter {     public object convert(object[] values, system.type targettype, object parameter, system.globalization.cultureinfo culture)     {         if (values[0] answer && values[1] containerbase && values[2] bool && values[3] bool /*targettype == typeof(visibility)*/)         {             var imageadequacyanswer = (answer)values[0];             var containerbase = (containerbase)values[1];             var missingtoptionselected = (bool)values[2];             var missingloptionselected = (bool)values[3];              if (imageadequacyanswer.value == ((int)imageadequacyanswers.notreadable).tostring() ||                 (missingtoptionselected && containerbase.name.contains("_t")) ||                 (missingloptionselected && containerbase.name.contains("_l")))             {                 return containerbase.getansweroptionbyvalue(((int)yesnoanswers.notapplicable).tostring());             }              return null;         }         else         {             return null;         }     } 

i thinking there might situation getting 2 different converters; hence 2 different data sets created , apparent race condition.

to solve possible issues such race condition recommend these 2 steps done; both of them done independently advised both together.

  1. within converter(s) put in lock sections , lock sync object stop dual access/creation of items go combos.
  2. create singleton based converter converter responsible own creation , 1 converter regardless of page needs converter gets exact same one.

to have converter create recommend generic base class created handles singleton creation of converter , servers converter(s). basing following code off of blog article entitled xaml: call binding converter without defining staticresource in xaml markup derived base class in c#.

in article 1 never creates static resource converter in xaml, directly call converter in xaml such as:

<window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"         xmlns:converters="clr-namespace:omega.operation.converters"         ...         >  <combo itemssource="{binding combodata,                         converter={ converters:endplateanswerfilterconverter }                        }"> 

to achieve direct binding of converter , creation of one converter in singleton following base class need implemented:

/// <summary> /// creates xaml markup can allow converters (which inheirit form class) called directly /// without specify static resource in xaml markup. /// </summary> public  class coverterbase<t> : markupextension t : class, new()  {     private static t _converter = null;      public coverterbase() { }      /// <summary>create , return static implementation of derived converter usage in xaml.</summary>     /// <returns>the static derived converter</returns>     public override object providevalue(iserviceprovider serviceprovider)     {         return _converter ?? (_converter = (t) activator.createinstance(typeof (t), null));     } } 

finally converter need specify base:

  namespace omega.operation.converters     {       public class endplateanswerfilterconverter : coverterbase<endplateanswerfilterconverter>,                                                         system.windows.data.ivalueconverter     {         public object convert(object value, type targettype, object parameter, system.globalization.cultureinfo culture)         {            lock (syncobject)            {}         }          public object convertback(object value, type targettype, object parameter, system.globalization.cultureinfo culture)         {           lock (syncobject)             {}                }     }     } 

Comments

Popular posts from this blog

javascript - Jquery show_hide, what to add in order to make the page scroll to the bottom of the hidden field once button is clicked -

javascript - Highcharts multi-color line -

javascript - Enter key does not work in search box -