WordPress database error: [INSERT, UPDATE command denied to user '51213-2'@'10.10.20.62' for table 'wp_options']INSERT INTO `wp_options` (`option_name`, `option_value`, `autoload`) VALUES ('_transient_doing_cron', '1714224046.1900470256805419921875', 'yes') ON DUPLICATE KEY UPDATE `option_name` = VALUES(`option_name`), `option_value` = VALUES(`option_value`), `autoload` = VALUES(`autoload`)
Today, it’s a blog on a tip to use the values of an enum as the source of an ItemsControl (ListBox, ComboBox, ListView, etc.) and display them nicely using attributes.<\/p>\n We’ll provide a localized description to be displayed and the value will still be available to the binding.<\/strong><\/p>\n In this post we’ll discover two very similar but differents solutions to this common issue. [table-of-content]<\/p>\n The foundation of the solution is based on reflection. The first item (Item1) of the tuple is the real value and the second item (Item2) is the text to be displayed. If the attribute is not found, then the value of the enum is used as a description.<\/p>\n The display attribute can be found in the System.ComponentModel.DataAnnotations.dll assembly.<\/p>\n [csharp] \/\/The method which fill the cache. \/\/if there is a display attribute on the field. return this._cache[type]; Here is an example of an enum with the correct DisplayAttributes set: [Display(Name = "My second name to display")] [Display(Name = "My third name to display")] ValueFourWithNoDisplayAttribute The first idea which comes in our WPF developer brain is to use a converter. This is easy to implement and pretty classic. The converter is defined in a resource scope available to the binding and the Type of the enum is provided by setting the Source property of the binding to the target enum type using the x:Type markup extension. Here is an example: The second idea, really less verbose, is to create a markup extension. The type of the enum will be provided as a parameter.<\/strong><\/p>\n Here is the code of the extension and the XAML usage of it below. public override object ProvideValue(IServiceProvider serviceProvider) \/\/RetrieveFromCacheOrAddIt snippet from above ! DisplayMemberPath and SelectedValuePath still need to be set but there is no converter to define and unusual binding source to use. If you want to localize the used text, you can provide the type of a resource file to use. <\/strong> For example if I change the previous enum to the definition below, I will have to create a resource file (Localized.resx) and add values for the keys ‘Value1’, ‘Value2’ and ‘Value3’. [Display(Name = "Value2", ResourceType = typeof(Localized))] [Display(Name = "Value3", ResourceType = typeof(Localized))] }[\/csharp] If I set the culture of the UI thread to french, the values will be translated in it. Tada ! I created a little demo which you can find in my DropBox folder<\/a>. It presents the two solutions. As you can see in the screenshot below, if no display attribute is set, the value of the enum is used: [\/table-of-content]<\/p>\n","protected":false},"excerpt":{"rendered":" Today, it’s a blog on a tip to use the values of an enum as the source of an ItemsControl (ListBox, ComboBox, ListView, etc.) and display them nicely using attributes. We’ll provide a localized description…<\/p>\n","protected":false},"author":3,"featured_media":863,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[6,4,5],"tags":[22,14,15,20],"_links":{"self":[{"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/posts\/835"}],"collection":[{"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/comments?post=835"}],"version-history":[{"count":25,"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/posts\/835\/revisions"}],"predecessor-version":[{"id":886,"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/posts\/835\/revisions\/886"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/media\/863"}],"wp:attachment":[{"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/media?parent=835"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/categories?post=835"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.jonathanantoine.com\/wp-json\/wp\/v2\/tags?post=835"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}
\n<\/p>\nFoundations<\/h3>\n
\nFor a provided type, the RetrieveFromCacheOrAddIt method read the Display attributes and create a list of tuples from it.<\/strong> A cache is created so the reflection is done only once by type.<\/p>\n
\n\/\/The cache to use
\nprivate readonly Dictionary<Type, List<Tuple<Object, Object>>>
\n _cache = new Dictionary<Type, List<Tuple<Object, Object>>>();<\/p>\n
\n private object RetrieveFromCacheOrAddIt(Type type)
\n {
\n \/\/if it is not already in cache
\n if (!this._cache.ContainsKey(type))
\n {
\n \/\/get the fields of the type via reflection
\n var fields = type.GetFields().Where(field => field.IsLiteral);
\n var values = new List<Tuple<Object, Object>>();
\n foreach (var field in fields)
\n {
\n \/\/retrieve the display attributes of the fields
\n var a = (DisplayAttribute[])field
\n .GetCustomAttributes(typeof(DisplayAttribute), false);
\n var valueOfField = field.GetValue(type);<\/p>\n
\n if (a.Length > 0)
\n {
\n var newTuple1 =
\n new Tuple<Object, Object>(valueOfField, a[0].GetName());
\n values.Add(newTuple1);
\n }
\n \/\/if not, use the value
\n else
\n {
\n var newTuple =
\n new Tuple<Object, Object>(valueOfField, valueOfField);
\n values.Add(newTuple);
\n }
\n }
\n this._cache[type] = values;
\n }<\/p>\n
\n }[\/csharp]<\/p>\n
\n[csharp] public enum MyEnum
\n {
\n [Display(Name = "My fist name to display")]
\n ValueOne,<\/p>\n
\n ValueTwo,<\/p>\n
\n ValueThird,<\/p>\n
\n }[\/csharp]<\/p>\nUse a converter<\/h3>\n
\n<\/strong>
\nHere is the codeof the converter and the regarding XAML usage.
\n[csharp] public object Convert(object value, Type targetType,
\n object parameter, System.Globalization.CultureInfo culture)
\n {
\n var type = value as Type;
\n return type == null ? null : RetrieveFromCacheOrAddIt(type);
\n }[\/csharp]<\/p>\n
\n[xml]
\n<DockPanel Margin="10">
\n <DockPanel.Resources>
\n <local:EnumToDictionnaryConverter x:Key="EnumToDictionnaryConverter" \/>
\n <\/DockPanel.Resources>
\n <TextBlock DockPanel.Dock="Left" Text="First solution : " FontWeight="Bold" \/>
\n <ComboBox DisplayMemberPath="Item2" SelectedValuePath="Item1"
\n SelectedValue="{Binding MyPropertyOnTheViewModel}"
\n ItemsSource="{Binding Source={x:Type local:MyEnum},
\n Converter={StaticResource EnumToDictionnaryConverter}}" \/>
\n<\/DockPanel>[\/xml]<\/p>\nUse a markup extension<\/h3>\n
\n[csharp] public class EnumToDictionnaryExtension : MarkupExtension
\n {
\n public Type TargetEnum { get; set; }
\n public EnumToDictionnaryExtension(Type type) { TargetEnum = type; }<\/p>\n
\n {
\n var type = TargetEnum;
\n if (type == null) return null;
\n return RetrieveFromCacheOrAddIt(type);
\n }<\/p>\n
\n}[\/csharp]<\/p>\n
\n[xml]
\n<ComboBox DisplayMemberPath="Item2" SelectedValuePath="Item1"
\n ItemsSource="{local:EnumToDictionnary {x:Type local:MyEnum}}" \/>[\/xml]<\/p>\nLocalisation – i18n<\/h3>\n
\nThe Display attribute GetName method will automatically pull the value from the resource file with the ‘name’ key of the attribute.<\/p>\n
\n[csharp]public enum MyEnum
\n{
\n [Display(Name = "Value1", ResourceType = typeof(Localized))]
\n ValueOne,<\/p>\n
\n ValueTwo,<\/p>\n
\n ValueThird,<\/p>\n
\nThen I can also create an another resource file named Localized.fr-FR.resx and translate the description in french.
\n<\/a><\/p>\n
\n[csharp]Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("fr-FR");[\/csharp]
\n<\/a><\/p>\nDemo<\/h3>\n
\n<\/a><\/p>\n