2009-02-11 8 views
22

sagen, dass ich eine Enumeration mit vier Werten haben:Wie kann ich ein WPF-Kombinationsfeld in XAML mit allen Elementen aus einer bestimmten Aufzählung füllen?

public enum CompassHeading 
{ 
    North, 
    South, 
    East, 
    West 
} 

Was XAML erforderlich wäre, eine ComboBox haben, mit diesen Elementen gefüllt werden?

<ComboBox ItemsSource="{Binding WhatGoesHere???}" /> 

Idealerweise müsste ich dafür keinen C# -Code einrichten.

+0

Ich lese gerade Eric Burkes letzten Post über eine Swing JComboBox-Klasse, die das tut, und dachte "Hey, ich schwöre, ich sah eine SO Frage zu diesem ..." Ich war nahe, aber Sie wollen WPF, nicht Java/Swing . Wie auch immer, hier ist es für die Nachwelt: http://stuffthathappens.com/blog/2009/02/10/a-swing-jcombobox-for-enums/ – JMD

Antwort

23

können Sie die Object, dies zu tun:

<ObjectDataProvider MethodName="GetValues" 
    ObjectType="{x:Type sys:Enum}" x:Key="odp"> 
    <ObjectDataProvider.MethodParameters> 
     <x:Type TypeName="local:CompassHeading"/> 
    </ObjectDataProvider.MethodParameters> 
</ObjectDataProvider> 

<ComboBox ItemsSource="{Binding Source={StaticResource odp}}" /> 

ich die Lösung hier gefunden:

http://bea.stollnitz.com/blog/?p=28

+0

Danke, diese Lösung scheint gut mit TwoWay-Bindung auch zu arbeiten. Beachten Sie, dass das IsSynchronizedWithCurrentItem = "true" ein Ablenkungsmanöver für diese Frage ist (Sie können es aus Gründen der Übersichtlichkeit für andere Besucher entfernen). –

+1

Dies unterstützt keine Lokalisierung. – Guge

+1

@Guge: Nein, das tut es nicht, aber Aufzählungen unterstützen auch keine Lokalisierung. Sie müssten für jede Lokalität eine andere Aufzählung erstellen, oder Sie müssten ein Attribut anhängen, das die Lokalisierungswerte für Sie erzeugen könnte (es würde eine Schlüsselsuche irgendeiner Art verwenden), in welchem ​​Fall die Frage und die Antwort nicht t gilt nicht mehr. – casperOne

6

Here ist ein detailliertes Beispiel dafür, wie Aufzählungen in WPF zu binden

Angenommen, Sie haben die folgende Enum

public enum EmployeeType  
{ 
    Manager, 
    Worker 
} 

Sie können dann in der Code-Behind binden

typeComboBox.ItemsSource = Enum.GetValues(typeof(EmployeeType)); 

oder verwenden Sie das Object

<ObjectDataProvider MethodName="GetValues" ObjectType="{x:Type sys:Enum}" x:Key="sysEnum"> 
    <ObjectDataProvider.MethodParameters> 
     <x:Type TypeName="local:EmployeeType" /> 
    </ObjectDataProvider.MethodParameters> 
</ObjectDataProvider> 

und jetzt können Sie binden im Markup

<ComboBox ItemsSource="{Binding Source={StaticResource sysEnum}}" /> 

Sie auch: Databinding an enum property to a ComboBox in WPF

1

Eine dritte Lösung:

Dies ist etwas mehr Arbeit im Voraus, besser ist auf lange Sicht einfacher, wenn Sie an viele Enums binden. Verwenden Sie einen Konverter, der den Typ der Enumeration als Parameter verwendet und ihn in ein Array von Strings als Ausgabe konvertiert.

In VB.NET:

Public Class EnumToNamesConverter 
    Implements IValueConverter 

    Public Function Convert(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert 
     Return [Enum].GetNames(DirectCast(value, Type)) 
    End Function 

    Public Function ConvertBack(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack 
     Throw New NotImplementedException() 
    End Function 
End Class 

Oder in C#:

public sealed class EnumToNamesConverter : IValueConverter 
{ 
    object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
    return Enum.GetNames(value.GetType()); 
    } 

    object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
    throw New NotSupportedException() 
    } 
} 

Dann in Ihrem Application.xaml, fügen Sie eine globale Ressource diesen Konverter zuzugreifen:

<local:EnumToNamesConverter x:Key="EnumToNamesConverter" /> 

Schließlich verwenden der Konverter in allen XAML-Seiten, wo Sie die Werte von allen Enum ...

<ComboBox ItemsSource="{Binding 
         Source={x:Type local:CompassHeading}, 
         Converter={StaticResource EnumToNamesConverter}}" /> 
+0

Hallo maranite2, ich mag das Aussehen dieser Lösung, aber ich konnte es nicht mit TwoWay Bindung arbeiten.Die Bindung funktioniert von der Kontrolle zu den Daten (wenn ich speichere), aber es funktioniert nicht von zu kontrollierenden Daten (das Kombinationsfeld ist anfänglich leer, wo ein Wert ausgewählt sein sollte). –

3

Für eine Schritt-für-Schritt-Anleitung der Alternativen und Ableitungen der Technik, versuchen Sie diese Web-Seite:

The Missing .NET #7: Displaying Enums in WPF

Dieser Artikel beschreibt eine Methode, die Darstellung bestimmter Werte überschrieben und . Ein gutes Buch mit vielen Codebeispielen.

14

ich eine Object denke mit zu tun, dass wirklich langweilig ist ... Ich habe einen prägnanten Vorschlag (ja, ich weiß, es ist ein bisschen spät ...), eine Markup-Erweiterung mit:

<ComboBox ItemsSource="{local:EnumValues local:EmployeeType}"/> 

hier ist der Code für die Markup-Erweiterung:

[MarkupExtensionReturnType(typeof(object[]))] 
public class EnumValuesExtension : MarkupExtension 
{ 
    public EnumValuesExtension() 
    { 
    } 

    public EnumValuesExtension(Type enumType) 
    { 
     this.EnumType = enumType; 
    } 

    [ConstructorArgument("enumType")] 
    public Type EnumType { get; set; } 

    public override object ProvideValue(IServiceProvider serviceProvider) 
    { 
     if (this.EnumType == null) 
      throw new ArgumentException("The enum type is not set"); 
     return Enum.GetValues(this.EnumType); 
    } 
} 
+0

Ich habe eine fast exakte Klasse für Sie entwickelt, ohne Ihre zu sehen. Mine fügt einen weiteren Check hinzu: 'enumType.IsEnum' vor der return-Anweisung. –

3

das ist wie Fluchen in einer Kirche sein, aber ich mag jeden ComboBoxItem explizit aus den folgenden Gründen in der XAML erklären:

  • Wenn ich eine Lokalisierung brauche, kann ich den XAML einem Übersetzer geben und den Code für mich behalten.
  • Wenn ich Enumerationswerte habe, die für eine bestimmte ComboBox nicht geeignet sind, muss ich sie nicht zeigen.
  • Die Reihenfolge der Enums wird im XAML bestimmt, nicht unbedingt im Code.
  • Die Anzahl der Enum-Werte zur Auswahl ist normalerweise nicht sehr hoch. Ich würde Enums mit Hunderten von Werten einen Code-Geruch einräumen.
  • Wenn ich auf einigen der ComboBoxItems Grafiken oder andere Verzierungen benötige, wäre es am einfachsten, sie einfach in XAML zu platzieren, wo sie statt einiger kniffliger Template-/Trigger-Sachen liegt.
  • Keep It Simple Stupid

C# Beispielcode:

public enum number { one, two, three }; 

public partial class MainWindow : Window, INotifyPropertyChanged 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
     this.DataContext = this; 
    } 

    private number _number = number.one; 
    public number Number 
    { 
     get { return _number; } 
     set { 
      if (_number == value) 
       return; 
      _number = value; 
      if (PropertyChanged != null) 
       PropertyChanged(this, new PropertyChangedEventArgs("Number")); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
} 

XAML-Code:

<Window x:Class="WpfApplication6.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="MainWindow" Height="480" Width="677"> 
<Grid> 
    <ComboBox SelectedValue="{Binding Number}" SelectedValuePath="Tag"> 
     <ComboBoxItem Content="En" Tag="One"/> 
     <ComboBoxItem Content="To" Tag="Two"/> 
     <ComboBoxItem Content="Tre" Tag="Three"/> 
    </ComboBox> 
</Grid> 

Wie Sie lokalisiert sehen können, hat sich die XAML worden Norwegisch, ohne dass Änderungen am C# -Code erforderlich sind.

+1

Und Sie erhalten Design-Time-Support aus der Box – surfen