Est-il possible d'utiliser la méthode ObjectDataProvider pour lier une ListBox à une énumération, et de lui donner un style pour afficher l'attribut Description ? Dans l'affirmative, comment s'y prendre ?
Réponses
Trop de publicités?Oui, c'est possible. Ceci va le faire. Disons que nous avons l'enum
public enum MyEnum
{
[Description("MyEnum1 Description")]
MyEnum1,
[Description("MyEnum2 Description")]
MyEnum2,
[Description("MyEnum3 Description")]
MyEnum3
}
Ensuite nous pouvons utiliser l'ObjectDataProvider comme
xmlns:MyEnumerations="clr-namespace:MyEnumerations"
<ObjectDataProvider MethodName="GetValues"
ObjectType="{x:Type sys:Enum}"
x:Key="MyEnumValues">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="MyEnumerations:MyEnum" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
Et pour la ListBox, nous définissons le ItemsSource à MyEnumValues et appliquons un ItemTemplate avec un Converter.
<ListBox Name="c_myListBox" SelectedIndex="0" Margin="8"
ItemsSource="{Binding Source={StaticResource MyEnumValues}}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource EnumDescriptionConverter}}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Et dans le convertisseur, nous récupérons la description et la renvoyons
public class EnumDescriptionConverter : IValueConverter
{
private string GetEnumDescription(Enum enumObj)
{
FieldInfo fieldInfo = enumObj.GetType().GetField(enumObj.ToString());
object[] attribArray = fieldInfo.GetCustomAttributes(false);
if (attribArray.Length == 0)
{
return enumObj.ToString();
}
else
{
DescriptionAttribute attrib = attribArray[0] as DescriptionAttribute;
return attrib.Description;
}
}
object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Enum myEnum = (Enum)value;
string description = GetEnumDescription(myEnum);
return description;
}
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return string.Empty;
}
}
La méthode GetEnumDescription devrait probablement aller ailleurs, mais vous avez compris l'idée :)
Consulte GetEnumDescription comme méthode d'extension .
Si vous vous liez à l'Enum, vous pourriez probablement le convertir en description grâce à un IValueConverter.
Voir Lier les ComboBox aux enums... en Silverlight ! pour une description de la manière d'y parvenir.
Voir http://msdn.microsoft.com/en-us/library/system.Windows.data.ivalueconverter.aspx pour plus d'informations.
Une autre solution serait de créer un MarkupExtension qui génère les éléments de type enum. Cela rend le xaml plus compact et plus lisible.
using System.ComponentModel;
namespace EnumDemo
{
public enum Numbers
{
[Description("1")]
One,
[Description("2")]
Two,
Three,
}
}
Exemple d'utilisation :
<Window x:Class="EnumDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:EnumDemo">
<ListBox ItemsSource="{local:EnumToCollection EnumType={x:Type local:Numbers}}"/>
</Window>
Mise en œuvre de MarkupExtension
using System;
using System.ComponentModel;
using System.Linq;
using System.Windows.Markup;
namespace EnumDemo
{
public class EnumToCollectionExtension : MarkupExtension
{
public Type EnumType { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (EnumType == null) throw new ArgumentNullException(nameof(EnumType));
return Enum.GetValues(EnumType).Cast<Enum>().Select(EnumToDescriptionOrString);
}
private string EnumToDescriptionOrString(Enum value)
{
return value.GetType().GetField(value.ToString())
.GetCustomAttributes(typeof(DescriptionAttribute), false)
.Cast<DescriptionAttribute>()
.FirstOrDefault()?.Description ?? value.ToString();
}
}
}
Vous pouvez définir un fichier ressource dans votre projet (fichier *.resx). Dans ce fichier, vous devez définir des "paires clé-valeur", comme ceci :
"YellowCars" : "Yellow Cars",
"RedCars" : "Red Cars",
et ainsi de suite...
Les clés sont égales à vos entrées d'enum, quelque chose comme ceci :
public enum CarColors
{
YellowCars,
RedCars
}
et ainsi de suite...
Lorsque vous utilisez WPF, vous pouvez implémenter dans votre code XAML, quelque chose comme ceci :
<ComboBox ItemsSource="{Binding Source={StaticResource CarColors}}" SelectedValue="{Binding CarColor, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource CarColorConverter}}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Ensuite, vous devez écrire votre convertisseur, quelque chose comme ça :
using System;
using System.Globalization;
using System.Resources;
using System.Windows.Data;
public class CarColorConverter : IValueConverter
{
private static ResourceManager CarColors = new ResourceManager(typeof(Properties.CarColors));
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var key = ((Enum)value).ToString();
var result = CarColors.GetString(key);
if (result == null) {
result = key;
}
return result;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Ma réponse arrive 7 ans trop tard ;-) Mais peut-être qu'elle peut servir à quelqu'un d'autre !
Oui, possible.
ListBox
peut nous aider à le faire, sans convertisseur.
Les étapes de cette méthode sont les suivantes :
créer une ListBox et définir la source d'éléments de la ListBox comme une énumération et lier l'élément sélectionné de la ListBox à la propriété sélectionnée.
Ensuite, chaque ListBoxItem sera créé.
-
Étape 1 : définissez votre Enum.
public enum EnumValueNames { EnumValueName1, EnumValueName2, EnumValueName3 }
Ajoutez ensuite la propriété ci-dessous à votre DataContext (ou ViewModel de MVVM), qui enregistre l'élément sélectionné qui est coché.
public EnumValueNames SelectedEnumValueName { get; set; }
-
Étape 2 : ajoutez l'enum aux ressources statiques de votre fenêtre, UserControl ou grille, etc.
<Window.Resources> <ObjectDataProvider MethodName="GetValues" ObjectType="{x:Type system:Enum}" x:Key="EnumValueNames"> <ObjectDataProvider.MethodParameters> <x:Type TypeName="local:EnumValueNames" /> </ObjectDataProvider.MethodParameters> </ObjectDataProvider> </Window.Resources>
-
Étape 3 : Utilisez la boîte de liste pour remplir chaque élément
<ListBox ItemsSource="{Binding Source={StaticResource EnumValueNames}}" SelectedItem="{Binding SelectedEnumValueName, Mode=TwoWay}" />
Références : https://www.codeproject.com/Articles/130137/Binding-TextBlock-ListBox-RadioButtons-to-Enums