I have a class:
public class AccountDetail { public DetailScope Scope { get { return scope; } set { scope = value; } } public string Value { get { return this.value; } set { this.value = value; } } private DetailScope scope; private string value; public AccountDetail(DetailScope scope, string value) { this.scope = scope; this.value = value; } }
and an enum:
public enum DetailScope { Private, Business, OtherDetail }
Lastly, I have a .xaml file:
<Window x:Class="Gui.Wpf.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Test" SizeToContent="WidthAndHeight"> <Grid> <ComboBox Name="ScopeComboBox" Width="120" Height="23" Margin="12" /> </Grid> </Window>
I would like to do two things:
DetailsScope
enum values to the combo box values. I don't wish to bind enum values directly because the last enum value would be OtherDetail
instead of Other detail
(added a space character and small letter 'd'). AccountDetail
object. Could you help me out? Thanks.
Update: I found this post http://blogs.msdn.com/b/wpfsdk/archive/2007/02/22/displaying-enum-values-using-data-binding.aspx. I need something similar.
A pretty easy way to do this is to use an ObjectDataProvider
<ObjectDataProvider MethodName="GetValues" ObjectType="{x:Type sys:Enum}" x:Key="DetailScopeDataProvider"> <ObjectDataProvider.MethodParameters> <x:Type TypeName="local:DetailScope" /> </ObjectDataProvider.MethodParameters> </ObjectDataProvider>
Use the ObjectDataProvider as the ItemsSource for the ComboBox, bind SelectedItem to the Scope property and apply a converter for the display of each ComboBoxItem
<ComboBox Name="ScopeComboBox" ItemsSource="{Binding Source={StaticResource DetailScopeDataProvider}}" SelectedItem="{Binding Scope}" Width="120" Height="23" Margin="12"> <ComboBox.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Converter={StaticResource CamelCaseConverter}}"/> </DataTemplate> </ComboBox.ItemTemplate> </ComboBox>
And in the converter you can use Regex for CamelCase string splitter found in this question. I used the most advanced version but you can probably use a simplier one. OtherDetail + the regex = Other Detail. Making return value lower and then return a string with first Character UpperCase should give you expected result
public class CamelCaseConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { string enumString = value.ToString(); string camelCaseString = Regex.Replace(enumString, "([a-z](?=[A-Z])|[A-Z](?=[A-Z][a-z]))", "$1 ").ToLower(); return char.ToUpper(camelCaseString[0]) + camelCaseString.Substring(1); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return value; } }
The way I have always done it is as follows. The beauty of this solution is that it is completely generic, and can be re-used for any enumeration types.
1) When you define an enumeration make use of some custom attributes to give a little information. In this example I've used Browsable(false) to indicate that this enumerator is internal, and I don't want to see this option in a combo box. Description("") allows me to specify a Display name for the enumeration.
public enum MyEnumerationTypeEnum { [Browsable(false)] Undefined, [Description("Item 1")] Item1, [Description("Item 2")] Item2, Item3 }
2) Define a class which I've called EnumerationManager. This is a generic class that analyzes an Enumeration type and generates a list of values. If an enumerator has Browsable set to false it will be skipped. If it has a Description attribute then it will use the description string as the display name. If no description is found it will just show the default string of the enumerator.
public class EnumerationManager { public static Array GetValues(Type enumeration) { Array wArray = Enum.GetValues(enumeration); ArrayList wFinalArray = new ArrayList(); foreach(Enum wValue in wArray) { FieldInfo fi = enumeration.GetField(wValue.ToString()); if(null != fi) { BrowsableAttribute[] wBrowsableAttributes = fi.GetCustomAttributes(typeof(BrowsableAttribute),true) as BrowsableAttribute[]; if(wBrowsableAttributes.Length > 0) { // If the Browsable attribute is false if(wBrowsableAttributes[0].Browsable == false) { // Do not add the enumeration to the list. continue; } } DescriptionAttribute[] wDescriptions = fi.GetCustomAttributes(typeof(DescriptionAttribute),true) as DescriptionAttribute[]; if(wDescriptions.Length > 0) { wFinalArray.Add(wDescriptions[0].Description); } else wFinalArray.Add(wValue); } } return wFinalArray.ToArray(); } }
3) In your xaml add a section in your ResourceDictionary
<ObjectDataProvider MethodName="GetValues" ObjectType="{x:Type l:EnumerationManager}" x:Key="OutputListForMyComboBox"> <ObjectDataProvider.MethodParameters> <x:Type TypeName="l:MyEnumerationTypeEnum" /> </ObjectDataProvider.MethodParameters> </ObjectDataProvider>
4) Now just bind the ItemsSource of your combobox to this key we just defined in the resource dictionary
<ComboBox Name="comboBox2" ItemsSource="{Binding Source={StaticResource OutputListForMyComboBox}}" />
If you try this code using my enumeration above you should see 3 items in your combo box:
Item 1 Item 2 Item3
Hope this helps.
EDITS: If you add the implementation of the LocalizableDescriptionAttribute and use that instead the Description attribute that I was using that would be perfect.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With