2009-02-11 4 views
22

Dire che ho un enum con quattro valori:Come posso compilare una casella combinata WPF in XAML con tutti gli elementi di una determinata enumerazione?

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

Cosa XAML verrebbe richiesto di avere un controllo ComboBox essere popolato con queste macchine?

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

Idealmente non avrei dovuto impostare il codice C# per questo.

+0

Ho appena letto il post recente di Eric Burke su una classe Swing JComboBox che fa questo, e ho pensato "Ehi, giuro di aver visto una domanda così su questo ..." ero vicino, ma tu vuoi WPF, non Java/Swing . Comunque, eccolo per i posteri: http://stuffthathappens.com/blog/2009/02/10/a-swing-jcombobox-for-enums/ – JMD

risposta

23

È possibile utilizzare l'ObjectDataProvider per fare questo:

<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}}" /> 

ho trovato la soluzione qui:

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

+0

Grazie, questa soluzione sembra funzionare bene anche con il binding TwoWay. Si noti che IsSynchronizedWithCurrentItem = "true" è un'aringa rossa per questa domanda (si potrebbe desiderare di rimuoverla per maggior chiarezza degli altri visitatori). –

+1

Questo non supporta la localizzazione. – Guge

+1

@Guge: No, no, ma le enumerazioni non supportano neanche la localizzazione. Dovresti creare una enumerazione diversa per ogni località, oppure dovresti allegare un attributo che potrebbe produrre i valori di localizzazione per te (userebbe una ricerca con chiave di qualche tipo), nel qual caso, la domanda e la risposta don ' t applicare più. – casperOne

6

Here è un esempio dettagliato di come legarsi a enumerazioni in WPF

Si supponga di avere il seguente enum

public enum EmployeeType  
{ 
    Manager, 
    Worker 
} 

È quindi possibile associare nel codebehind

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

o utilizzare l'ObjectDataProvider

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

e ora è possibile associare nel markup

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

Verificate anche: Databinding an enum property to a ComboBox in WPF

1

Una terza soluzione:

Questo è un po 'più di lavoro in anticipo, meglio è più facile a lungo termine se si sta vincolando a un sacco di Enum. Utilizzare un convertitore che accetta il tipo dell'enumerazione come parametro e lo converte in una matrice di stringhe come output.

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 

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

Poi, nel tuo Application.xaml, aggiungere una risorsa globale per accedere a questo convertitore:

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

Infine usare il convertitore in qualsiasi pagina XAML in cui sono necessari i valori di qualsiasi Enum ...

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

Ciao maranite2, mi piace l'aspetto di questa soluzione, ma non riuscivo a farlo funzionare con il binding TwoWay.Il binding funziona dal controllo ai dati (quando salvo) ma non funziona dai dati al controllo (la casella combinata è inizialmente vuota dove dovrebbe essere selezionato un valore). –

3

Per una guida passo-passo delle alternative e derivazioni della tecnica, provare questa pagina web:

The Missing .NET #7: Displaying Enums in WPF

questo articolo viene illustrato un metodo di rilevante la presentazione di alcuni valori come pure . Una buona lettura con molti esempi di codice.

14

Penso che utilizzando un ObjectDataProvider per farlo è davvero noioso ... Ho un suggerimento più concisa (sì lo so, è un po 'tardi ...), utilizzando un'estensione di markup:

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

Ecco il codice per l'estensione di markup:

[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

Mi sono avvicinato con una classe quasi esatta alla tua senza vedere la tua. Il mio aggiunge un altro controllo: 'enumType.IsEnum' prima dell'istruzione return. –

3

Questo può essere come bestemmiare in una chiesa, ma mi piacerebbe di dichiarare ogni ComboBoxItem esplicitamente nel codice XAML per i seguenti motivi:

  • Se ho bisogno di localizzazione, posso dare XAML a un traduttore e mantenere il codice per me.
  • Se sono presenti valori di enumerazione non adatti a un determinato componente ComboBox, non è necessario visualizzarli.
  • L'ordine di enumerazione è determinato in XAML, non necessariamente nel codice.
  • Il numero di valori di enumer da scegliere non è in genere molto alto. Considererei Enum con centinaia di valori un odore di codice.
  • Se ho bisogno di elementi grafici o altri ornamenti su alcuni ComboBoxItems, sarebbe più semplice inserirlo in XAML, a cui appartiene invece di alcuni elementi di Trigger/Template difficili.
  • Keep It Simple, Stupid

codice C# di esempio: il codice

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:

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

Come si può vedere, il codice XAML è stato localizzato a Norvegese, senza alcuna necessità di modifiche nel codice C#.

+1

E ricevi subito il supporto per la progettazione – surfen