40 votes

WPF Lier une ListBox à une énumération, afficher l'attribut Description

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 ?

103voto

Fredrik Hedblad Points 42772

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 .

3voto

Pieter van Ginkel Points 17057

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.

3voto

chviLadislav Points 278

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();
        }
    }
}

2voto

peter70 Points 92

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 !

0voto

Bravo Yeung Points 376

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X