binding - WPF ComboBox with CheckBoxes bound to flags enumeration TwoWay -
i in middle of creating wpf utility library i'm stuck on how create easy use enumeration converter in binding enumeration combobox control , when enumeration declared [flags] attribute, combobox contain checkboxes data bound it. solution needs generic easy use enumeration , suppose need fresh pair of eyes of experienced wpf developer.
so far i've come combination of objectdataprovider source of enum items , 2 converters, 1 itemssource , selectedvalue. used collectionview base class itemssource use currentchanged not work tried raise oncurrentchanged after collection has been notified checkbox being checked without converter's convertback being executed.
the problem data bound property combobox selectedvalue property bound, not updated unless i'll change selected item (not tick checkbox). i've set issynchronizedwithcurrentitem did not help.
how force updating of selectedvalue data bound object? have freedom of choice solution might involve custom attached properties, inheriting combobox etc. being new wpf think although solution right works, there can simpler way of getting it.
another issue how customize text displayed on combobox contain aggregated selections of ticked checkboxes.
i uploaded vs2012 project here. structure of project resembles real application resources held separately (for simplicity in app.xaml).
sorry have not included code there lot of code involved.
below xaml declaration checkbox bound standard enumeration (although enumeration used [flags]), works fine , further checkbox bound [flags] enumeration.
<combobox itemssource="{binding source={staticresource someitemssource}}" selectedvalue="{binding bindtosomeitems}" style="{staticresource enumcombobox}"/> <combobox itemssource="{binding bindtosomeitems, converter={local:localizedflagsenumconverter}}" issynchronizedwithcurrentitem="true" selectedvalue="{binding bindtosomeitems, mode=twoway, converter={local:selectedflagsenumconverter}}" style="{staticresource flagscombobox}" /> and resources (which explain usage of value converters):
<application.resources> <style x:key="enumcombobox" targettype="{x:type combobox}"> <setter property="itemtemplate"> <setter.value> <datatemplate> <textblock text="{binding path=.,mode=oneway, converter={local:localizedenumconverter}}" style="{x:null}"/> </datatemplate> </setter.value> </setter> </style> <style x:key="flagscombobox" targettype="{x:type combobox}"> <setter property="itemtemplate"> <setter.value> <datatemplate> <stackpanel orientation="horizontal"> <checkbox ischecked="{binding path=checked,mode=twoway}"/> <textblock text="{binding path=name,mode=oneway}"/> </stackpanel> </datatemplate> </setter.value> </setter> </style> </application.resources>
i use custom checkbox so. works , simply. see comments on top of class know how use it.
hope helps...
using system; using system.windows; using system.windows.controls; namespace hq.wpf.util.mycontrol { /// <summary> /// usage: bind enumflag , 2 way binding on enumvalue instead of ischecked /// example: <mycontrol:checkboxforenumwithflagattribute /// enumvalue="{binding simulationnaturetypetocreatestatscacheatendofsimulation, mode=twoway}" /// enumflag="{x:static core:simulationnaturetype.loadflow }">load flow results</mycontrol:checkboxforenumwithflagattribute> /// </summary> public class checkboxforenumwithflagattribute : checkbox { // ************************************************************************ public static dependencyproperty enumvalueproperty = dependencyproperty.register("enumvalue", typeof(object), typeof(checkboxforenumwithflagattribute), new propertymetadata(enumvaluechangedcallback)); public static dependencyproperty enumflagproperty = dependencyproperty.register("enumflag", typeof(object), typeof(checkboxforenumwithflagattribute), new propertymetadata(enumflagchangedcallback)); // ************************************************************************ public checkboxforenumwithflagattribute() { base.checked += checkboxforenumwithflag_checked; base.unchecked += checkboxforenumwithflag_unchecked; } // ************************************************************************ private static void enumvaluechangedcallback(dependencyobject dependencyobject, dependencypropertychangedeventargs dependencypropertychangedeventargs) { var checkboxforenumwithflag = dependencyobject checkboxforenumwithflagattribute; if (checkboxforenumwithflag != null) { checkboxforenumwithflag.refreshcheckboxstate(); } } // ************************************************************************ private static void enumflagchangedcallback(dependencyobject dependencyobject, dependencypropertychangedeventargs dependencypropertychangedeventargs) { var checkboxforenumwithflag = dependencyobject checkboxforenumwithflagattribute; if (checkboxforenumwithflag != null) { checkboxforenumwithflag.refreshcheckboxstate(); } } // ************************************************************************ public object enumvalue { { return getvalue(enumvalueproperty); } set { setvalue(enumvalueproperty, value); } } // ************************************************************************ public object enumflag { { return getvalue(enumflagproperty); } set { setvalue(enumflagproperty, value); } } // ************************************************************************ private void refreshcheckboxstate() { if (enumvalue != null) { if (enumvalue enum) { type underlyingtype = enum.getunderlyingtype(enumvalue.gettype()); dynamic valueasint = convert.changetype(enumvalue, underlyingtype); dynamic flagasint = convert.changetype(enumflag, underlyingtype); base.ischecked = ((valueasint & flagasint) > 0); } } } // ************************************************************************ private void checkboxforenumwithflag_checked(object sender, routedeventargs e) { refreshenumvalue(); } // ************************************************************************ void checkboxforenumwithflag_unchecked(object sender, routedeventargs e) { refreshenumvalue(); } // ************************************************************************ private void refreshenumvalue() { if (enumvalue != null) { if (enumvalue enum) { type underlyingtype = enum.getunderlyingtype(enumvalue.gettype()); dynamic valueasint = convert.changetype(enumvalue, underlyingtype); dynamic flagasint = convert.changetype(enumflag, underlyingtype); dynamic newvalueasint = valueasint; if (base.ischecked == true) { newvalueasint = valueasint | flagasint; } else { newvalueasint = valueasint & ~flagasint; } if (newvalueasint != valueasint) { object o = enum.toobject(enumvalue.gettype(), newvalueasint); enumvalue = o; } } } } // ************************************************************************ } }
Comments
Post a Comment