Laden...

GenericEnumConverter für WPF - Anzeige von userspezifischen Namen für Werte + Anzeige aller Werte

Erstellt von talla vor 13 Jahren Letzter Beitrag vor 13 Jahren 4.007 Views
talla Themenstarter:in
6.862 Beiträge seit 2003
vor 13 Jahren
GenericEnumConverter für WPF - Anzeige von userspezifischen Namen für Werte + Anzeige aller Werte

Hallo zusammen,

Beispiele für WPF ValueConverter kann man nie genug haben, daher auch eins von mir.

Der GenericEnumConverter erlaubt es für die Werte eines Enums einen Anzeigestring festzulegen und diesen anzuzeigen wenn gegen einen Wert dieses Enums gebunden wird. Zusätzlich besitz der Converter ein statisches Property welches alle mögliche Werte des Enums zurückgibt.

Der Converter:
Zum festlegen des Anzeigenamens gibt es ein einfaches Attribut:

    [AttributeUsage(AttributeTargets.Field)]
    public class EnumDisplayAttribute : Attribute
    {
        public EnumDisplayAttribute(string displayValue)
        {
            DisplayValue = displayValue;
        }

        public string DisplayValue { get; private set; }
    }

Der Converter ist ebenfalls recht einfach gehalten:

public class GenericEnumConverter<T> : IValueConverter
	{
		private static readonly Dictionary<T, string> TypeToDisplayStringDictionary = new Dictionary<T, string>();
		private static readonly Dictionary<string, T> DisplayStringToTypeDictionary = new Dictionary<string, T>();

		public static List<string> PossibleValues { get; private set; }

		static GenericEnumConverter()
		{
			PossibleValues = new List<string>();
			var fields = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Static);
			foreach (var field in fields)
			{
				var attr = field.GetCustomAttributes(typeof(EnumDisplayAttribute), false) as EnumDisplayAttribute[];
				if (attr != null)
					if (attr.Length > 0)
					{
						// Fügt den Anzeigewert der Liste der möglichen Einträge hinzu
						PossibleValues.Add(attr[0].DisplayValue);
						// Fügt den originalen Namen der Liste der möglichen Einträge hinzu
						// Beim einkommentieren muss drauf geachtet werden das auch die Logik von Convert/ConvertBack invertiert werden muss.
						// PossibleValues.Add(field.GetValue(null).ToString());
						TypeToDisplayStringDictionary.Add((T)field.GetValue(null), attr[0].DisplayValue);
						DisplayStringToTypeDictionary.Add(attr[0].DisplayValue, (T)field.GetValue(null));
					}
			}
		}

		public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			string result;
			TypeToDisplayStringDictionary.TryGetValue((T)value, out result);
			return result;
		}

		public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
		{
			T type;
			DisplayStringToTypeDictionary.TryGetValue(value as string ?? String.Empty, out type);
			return type;
		}
	}

Der statische Konstruktor durchsucht das Enum nach den Attributen und füllt zwei Dictionaries - jeweils eins für eine Convertierungsrichtung. Aus diesn wird dann im Convert bzw. ConvertBack einfach der passende Wert rausgesucht. Zusätzlich wird im Konstruktor das Property mit den möglichen Werten befüllt.

Anwendung:
Für die Anwendung muss nun vom Converter eine spezielle Ableitung erzeugt werden:

 public class SampleEnumConverter : GenericEnumConverter<SampleEnum> {}

Dies ist notwending da XAML keine Generics für diesem Anwendungsfall erlaubt. SampleEnum ist hierbei der Enum Typ welchen ich im Beispiel verwende.
Dieser ist so aufgebaut:

    public enum SampleEnum
    {
        [EnumDisplay("Ungültiger Wert")]
        Undefined,
        [EnumDisplay("Wert 1")]
        Value1,
        [EnumDisplay("Wert 2")]
        Value2,
        [EnumDisplay("Wert 3")]
        Value3
    }

Die Beispielanwendung hat nun eine ComboBox gegen die solch ein Enumproperty gebunden ist und zeigt in zwei TextBoxen den Wert diese Properties an - einmal als normaler Wert und einmal den Anzeigestring.
Der kleine Kniff hierbei ist, dass die ComboBox selber gegen die Liste der möglichen Werte bindet um diese selektieren zu können und das SelectedItem bindet gegen das EnumProperty welches durch die Auswahl in der ComboBox geändert werden soll.

<Window 
		x:Class="EnumConverterTestapp.MainWindow" 
		xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
		xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
		xmlns:local="clr-namespace:EnumConverterTestapp"
		Title="MainWindow" 
		SizeToContent="WidthAndHeight">
		<Window.Resources>
			<!-- Objekte für unser Datum gegen welches später gebunden wird, und für den Converter anlegen-->
			<ObjectDataProvider 
				x:Key="SampleData" 
				ObjectType="{x:Type local:SampleDataClass}" />
			<local:SampleEnumConverter 
				x:Key="MySampleEnumConverter" />
		</Window.Resources>
		<StackPanel>
			<ComboBox 
				ItemsSource="{x:Static local:SampleEnumConverter.PossibleValues}" 
				SelectedItem="{Binding Path=Sample ,Source={StaticResource SampleData}, Converter={StaticResource MySampleEnumConverter}}" />
			<!-- Anzeige von Anzeige und realem Wert des Enums -->
			<TextBlock 
				Text="Nachfolgend der selektierte Wert, mit und ohne EnumDisplayAttribute" 
				Background="LightBlue" />
			<TextBlock 
				Text="{Binding Path=Sample ,Source={StaticResource SampleData}}" />
			<TextBlock 
				Text="{Binding Path=Sample ,Source={StaticResource SampleData}, Converter={StaticResource MySampleEnumConverter}}" />
		</StackPanel>
	</Window>

Der Converter ist bewusst einfach gehalten, es gibt noch viele Stellen die ergänzt werden können. Per zusätzliches Property könnte z.B. gesteuert werden ob die Liste der möglichen Werte die Anzeigestrings oder die normalen Werte beinhaltet. Ebenso ist die Lokalisierung der Anzeigestrings nicht umgesetzt. Dies ist aber ebenfalls leicht ergänzbar indem z.B. der Converter mit einem Property für die zu verwendene Sprache erweitert wird, das Attribut für die Enums nur noch eine Art Text Id entsprich und der Converter dann aus den Sprachressourcen den für die ID den entsprechenden Wert verwendet.

Ich hoffe der eine oder andere findet dafür ne Anwendung.

Ideen und Meinungen dazu sind gern willkommen.

MfG Talla
Schlagwörter: WPF, IValueConverter, ValueConverter, Enum, Binding, Databinding

Baka wa shinanakya naoranai.

Mein XING Profil.