2009-02-11 14 views
22

Decir que tengo una enumeración con cuatro valores:¿Cómo puedo completar un cuadro combinado de WPF en XAML con todos los elementos de una enumeración dada?

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

lo que se requeriría XAML tener un ComboBox poblarse de estos equipos?

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

Lo ideal sería no tener que configurar el código C para esto.

+0

Acabo de leer la reciente publicación de Eric Burke sobre una clase Swing JComboBox que hace esto, y pensé "Oye, te juro que vi una ASISTA pregunta sobre esto ..." Estaba cerca, pero quieres WPF, no Java/Swing . De todos modos, aquí está para la posteridad: http://stuffthathappens.com/blog/2009/02/10/a-swing-jcombobox-for-enums/ – JMD

Respuesta

23

Puede utilizar el ObjectDataProvider para hacer esto:

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

he encontrado la solución aquí:

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

+0

Gracias, esta solución parece funcionar bien con el enlace de TwoWay también. Tenga en cuenta que IsSynchronizedWithCurrentItem = "true" es un arenque rojo para esta pregunta (es posible que desee eliminarlo para mayor claridad de otros visitantes). –

+1

Esto no es compatible con la localización. – Guge

+1

@Guge: No, no es así, pero las enumeraciones tampoco admiten la localización. Tendría que crear una enumeración diferente para cada localidad, o debería adjuntar un atributo que podría producir los valores de localización para usted (usaría una búsqueda con clave de algún tipo), en cuyo caso, la pregunta y la respuesta no se realizarían. t aplicar más – casperOne

6

Here es un ejemplo detallado de cómo se unen a las enumeraciones en WPF

Supongamos que tiene la siguiente enumeración

public enum EmployeeType  
{ 
    Manager, 
    Worker 
} 

A continuación, puede unirse en el código subyacente

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

o utilizar el ObjectDataProvider

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

y ahora se puede unir en el marcado

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

También puedes ver: Databinding an enum property to a ComboBox in WPF

1

Una tercera solución:

Esto supone un poco más de trabajo por adelantado, mejor es más fácil a largo plazo si enlaza muchos Enumera. Utilice un convertidor que tome el tipo de enumeración como un parámetro, y lo convierta en una matriz de cadenas como salida.

En 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 en 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() 
    } 
} 

Luego, en su Application.xaml, añadir un recurso global para acceder a este convertidor:

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

utilizar último el convertidor en cualquier página XAML donde necesite los valores de cualquier Enum ...

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

Hola maranite2, me gusta el aspecto de esta solución, pero no pude conseguir que funcione con el enlace TwoWay.El enlace funciona desde el control a los datos (cuando guardo) pero no funciona desde los datos hasta el control (el cuadro combinado está inicialmente en blanco donde debería haber un valor seleccionado). –

3

Para una guía paso a paso de las alternativas y las derivaciones de la técnica, trate de esta página web:

The Missing .NET #7: Displaying Enums in WPF

Este artículo muestra un método de anular la presentación de ciertos valores, así . Una buena lectura con muchas muestras de código.

14

Creo que el uso de un ObjectDataProvider de hacerlo es muy tedioso ... tengo una sugerencia más concisa (sí, lo sé, es un poco tarde ...), utilizando una extensión de marcado:

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

aquí está el código para la extensión de marcado:

[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

Encontré una clase casi exacta con la tuya sin ver la tuya. El mío agrega un cheque más: 'enumType.IsEnum' antes de la declaración de devolución. –

3

Esto puede ser como juramento en una iglesia, pero me gustaría que declaren cada ComboBoxItem explícitamente en el XAML por las siguientes razones:

  • Si necesito localización, puedo entregar el XAML a un traductor y guardar el código para mí.
  • Si tengo valores enum que no son adecuados para un ComboBox dado, no es necesario que los muestre.
  • El orden de las enumeraciones se determina en el XAML, no necesariamente en el código.
  • El número de valores enum para elegir no suele ser muy alto. Consideraría los Enums con cientos de valores que un código huele.
  • Si necesito gráficos u otra ornamentación en algunos de los ComboBoxItems, sería más fácil simplemente ponerlo en XAML, donde pertenece en lugar de algunas cosas complicadas de Template/Trigger.
  • Keep It Simple, Stupid

código C# Ejemplo: código de

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> 

Como se puede ver, el XAML se ha localizado en Noruego, sin necesidad de cambios en el código C#.

+1

Y obtiene soporte de tiempo de diseño fuera de la caja – surfen

Cuestiones relacionadas