In my WP8 application I need to show a couple of radio buttons to let the user select a value out of an enum
. I don't want to hardcode either the value or the text (description) showed to the user. I would like my Model/ViewModel drive them for me.
As of now, this is what I have:
//enum defined in model
public enum Units
{
[Description ("Meters/km")]
Metric,
[Description ("Feet/Miles")]
Imperial
}
Converters defined to handle string and Boolean conversions
//<Summary>Converts ENum to boolean and back
// Convert: uses parameter passed in, returns true if current value of the Enum matches parameter
//ConvertBack: if value is true, sets the value of the ENum to parameter passed in
//</summary>
[ValueConversion (typeof (Enum), typeof (Boolean))]
public class EnumToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string parameterString = parameter as string;
if ( parameterString == null )
return DependencyProperty.UnsetValue;
if ( Enum.IsDefined (value.GetType (), value) == false )
return DependencyProperty.UnsetValue;
object parameterValue = Enum.Parse (value.GetType (), parameterString);
return parameterValue.Equals (value);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value.Equals (true) ? Enum.Parse(targetType, parameter as String) : DependencyProperty.UnsetValue;
}
}
//<Summary>Converts ENum to strings, uses Description for the parameter passed in, or parameter as string</summary>
[ValueConversion (typeof (Enum), typeof (String))]
public class EnumToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string parameterString = parameter as string;
if ( parameterString == null )
return DependencyProperty.UnsetValue;
if ( Enum.IsDefined (value.GetType (), value) == false )
return DependencyProperty.UnsetValue;
var desc = (value.GetType ().GetField (parameterString).GetCustomAttributes (typeof (DescriptionAttribute), false).FirstOrDefault() as DescriptionAttribute);
if ( desc != null )
return desc.Description;
else
return parameter.ToString ();
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException ();
}
}
In the XAML:
<Grid Margin="0,10,0,0">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Text="How do you measure distance?"
Margin="6,0,0,0"
Grid.ColumnSpan="2"
Grid.Row="0" />
<RadioButton Grid.Row="1"
Grid.Column="0"
Content="{Binding PreferredUnit, ConverterParameter=Metric, Converter={StaticResource EnumToStringConverter}}"
IsChecked="{Binding PreferredUnit, ConverterParameter=Metric, Converter={StaticResource EnumToBooleanConverter}, Mode=TwoWay}" />
<RadioButton Grid.Row="1"
Grid.Column="1"
Content="{Binding PreferredUnit, ConverterParameter=Imperial, Converter={StaticResource EnumToStringConverter}}"
IsChecked="{Binding PreferredUnit, ConverterParameter=Imperial, Converter={StaticResource EnumToBooleanConverter}, Mode=TwoWay}" />
</Grid>
Does anyone here think I am on the right track with my approach? Any suggestions on improving the code (in terms of logic, clarity, performance)?