it-swarm.com.de

WPF Bindet eine ListBox an ein Enum und zeigt das Beschreibungsattribut an

Ist es möglich, die ObjectDataProvider-Methode zu verwenden, um eine ListBox an eine Aufzählung zu binden und die Beschreibung attriibute irgendwie anzuzeigen? Wenn ja, wie würde man das machen ...?

33
Michal Ciechan

Ja, es ist möglich. Das wird es tun. Sagen wir, wir haben das Enum

public enum MyEnum
{
    [Description("MyEnum1 Description")]
    MyEnum1,
    [Description("MyEnum2 Description")]
    MyEnum2,
    [Description("MyEnum3 Description")]
    MyEnum3
}

Dann können wir den ObjectDataProvider als verwenden

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>

Und für die ListBox setzen wir die ItemsSource auf MyEnumValues ​​und wenden eine ItemTemplate mit einem Converter an.

<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>

Und im Konverter bekommen wir die Beschreibung und schicken sie zurück

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

Die GetEnumDescription-Methode sollte wahrscheinlich woanders hingehen, aber Sie haben die Idee :)

86
Fredrik Hedblad

Eine andere Lösung wäre eine benutzerdefinierte MarkupExtension , die die Elemente aus dem Aufzählungstyp generiert. Dies macht die XAML kompakter und lesbarer.

using System.ComponentModel;

namespace EnumDemo
{
    public enum Numbers
    {
        [Description("1")]
        One,

        [Description("2")]
        Two,

        Three,
    }
}

Anwendungsbeispiel:

<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>

Implementierung von 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();
        }
    }
}
2
chviLadislav

Wenn Sie an das Enum binden, können Sie dies möglicherweise über einen IValueConverter in die Beschreibung konvertieren.

See ComboBoxen an Enums binden ... in Silverlight! für eine Beschreibung, wie dies zu erreichen ist.

Weitere Informationen finden Sie unter http://msdn.Microsoft.com/en-us/library/system.windows.data.ivalueconverter.aspx .

2

Sie können in Ihrem Projekt eine Ressourcendatei definieren (* .resx-Datei). In dieser Datei müssen Sie "Schlüssel-Wert-Paare" definieren, etwa wie folgt:

"YellowCars" : "Yellow Cars",
"RedCars" : "Red Cars",

und so weiter...

Die Schlüssel sind mit Ihren Enum-Einträgen identisch, etwa wie folgt:

public enum CarColors
{
    YellowCars,
    RedCars
}

und so weiter...

Wenn Sie WPF verwenden, können Sie Folgendes in Ihren XAML-Code implementieren:

<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>

Dann müssen Sie Ihren Konverter schreiben, etwa so:

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

Meine Antwort kommt 7 Jahre zu spät ;-) Aber vielleicht kann es von jemand anderem benutzt werden!

1
peter70