2011-08-26 14 views
5

Tengo un modelo con una propiedad enum (en este caso, relacionado con las regulaciones de control de exportación). Cuando visualice el valor para el usuario, quiero mostrar una cadena correspondiente. Algunas veces esto está en ComboBox (donde el usuario puede seleccionar un valor), y algunas veces está en un TextBlock (donde es de solo lectura).Enlazar textblock con el valor del diccionario para la clave en XAML?

Ejemplo: para ExportRegulationType.EAR, quiero mostrar "EAR", mientras que para ExportRegulationType.DoNotExport, quiero mostrar "Do Not Export". Tenga en cuenta que no tengo ninguna necesidad de localización de idiomas, pero reconozco el problema ...

Actualmente, en mi ViewModel, tengo una propiedad que devuelve una cadena basada en el valor enum actual, y también otra propiedad que devuelve un Dictionary<ExportRegulationType, string>. Para los ComboBoxes, puedo vincular ItemsSource a la propiedad del diccionario, y para los TextBlocks, puedo enlazar a la propiedad de cadena. Esto funciona, pero es un poco torpe.

Dos preguntas:

1) Me parece que yo debería ser capaz de declarar el diccionario (con claves y valores) como un recurso estático en XAML (probablemente en App.xaml), y el uso que de el ItemsSource para la versión de ComboBox. Sin embargo, no puedo descifrar cómo declarar y referenciar tal cosa. ¿Cómo puedo hacer eso?

2) Suponiendo que lo anterior está en su lugar, creo que también podría configurar un enlace con el bloque de texto, por lo que en función de la propiedad enum, buscará la cadena en el diccionario.

He visto las siguientes preguntas relacionadas con un valor de enum static o dynamic. El primero no es adecuado, y el segundo no se responde ...

Estos deben ser solo XAML, y me permitirán eliminar los métodos de mi ViewModel (que tiene solo la propiedad enumerada ExportRegulationType expuesta). son estos posibles

Editar: información adicional:.

En la aplicación, voy a tener muchos conjuntos diferentes de puntos de vista, modelos y ViewModels Sin embargo, como los reglamentos de control de exportaciones son un requisito común y consistente, Estoy usando la composición para mantenerla SECA, es decir, los Modelos A y B tienen ambos un modelo ExportControl. ViewModels A1, A2, B1 y B2 tendrán ve un ExportControlViewModel. Las vistas tendrán controles vinculados al ExportControlViewModel de su ViewModel. Las vistas tendrán un ComboBox o un TextBlock, pero no ambos (Dependiendo de si el usuario puede cambiar el valor).

+0

Agregué C# como una etiqueta para que las respuestas obtuvieran resaltado de sintaxis –

Respuesta

3

No sé si esto funcionará para su caso, pero aquí hay una posible solución. En su modelo de vista, exponer una propiedad ExportRegulationType y luego crear un value converter para mostrar la cadena deseada.

En primer lugar crear su convertidor de valores:

class ExportRegulationTypeToStringConverter: IValueConverter 
{ 
    #region IValueConverter Members 

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     ExportRegulationType regType = (ExportRegulationType)value; 

     switch(regType) 
     { 
      case ExportRegulationType.EAR: 
       return "EAR"; 
      case ExportRegulationType.DoNotExport: 
       return "Do Not Export"; 

      //handle other cases 
     } 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     return Binding.DoNothing; 
    } 

    #endregion 
} 

A continuación, agregue una referencia a su convertidor en su xaml. local es el espacio de nombre en el que se encuentra su clase.

<local:ExportRegulationTypeToStringConverter x:Key="exportRegConverter" /> 

Finalmente, establezca el valor de su cuadro de texto para usar el convertidor. pathToEnum es la propiedad expuesta en su ViewModel del tipo ExportRegulationType.

<TextBlock Text="{Binding pathToEnum, Converter={StaticResource exportRegConverter}}" /> 

Uso ObjectDataProvider para llenar el cuadro combinado con los valores de la enumeración.

<Window.Resources> 
<ObjectDataProvider x:Key="dataFromEnum" 
    MethodName="GetValues" ObjectType="{x:Type System:Enum}"> 
     <ObjectDataProvider.MethodParameters> 
      <x:Type TypeName="local:ExportRegulationType"/> 
     </ObjectDataProvider.MethodParameters> 
</ObjectDataProvider> 
</Window.Resources> 

Ahora vamos a crear el cuadro combinado y utilizar un estilo recipiente con nuestra value converter para visualizar las cuerdas deseadas para nuestra enumeración.

<ComboBox ItemsSource="{Binding Source={StaticResource dataFromEnum}}"> 
    <ComboBox.ItemContainerStyle> 
     <Style TargetType="ComboBoxItem"> 
      <Setter Property="Content" Value="{Binding Converter={StaticResource exportRegConverter}}" /> 
     </Style> 
    </ComboBox.ItemContainerStyle> 
</ComboBox> 
+0

Me gustaría poder elegir dos respuestas; ¡Te doy el crédito de ser rápido en la dirección correcta y de necesitar más representantes! – mbmcavoy

+0

Ah, como una nota: el uso de ComboBox.ItemContainerStyle casi funcionó: los elementos en la lista desplegable eran correctos. Sin embargo, cuando se seleccionó un elemento y se cierra el menú desplegable, se mostró el valor enum.ToString(). Usar una plantilla de datos en su lugar funciona correctamente. – mbmcavoy

1

Utilice un ObjectDataProvider a continuación, enlazar artículos del ComboBox a ella, y ajuste "DisplayMemberPath" a "Valor".

Lo que esto debe hacer es mostrar los valores de su diccionario, pero en el código subyacente SelectedValue es una KeyValuePair<>.

Para su bloque de texto, utilice un Binding usando ElementName=yourcombobox y Path=SelectedItem:

<TextBlock Text="{Binding SelectedItem, ElementName=yourcombobox}" /> 

Déjame saber cómo va =)

2

En lugar de la Dictionary tiene otra opción.

Véase la siguiente pregunta: WPF Binding a ListBox to an enum, displaying the Description Attribute

Se podría añadir un atributo Description a sus enumeraciones como esto

public enum ExportRegulationType 
{ 
    [Description("EAR")] 
    EAR, 
    [Description("Do Not Export")] 
    DoNotExport 
} 

Y cuando se quiere mostrarlo, sólo puede utilizar EnumDescriptionConverter convertidor encuentra en la pregunta he vinculado

+0

Slick. Como. ¡Infierno! Me encanta que la definición de cadena esté integrada con la enumeración, y que el convertidor (con un ajuste menor) sea genérico para cualquier Enum y sea elegante sin el atributo de descripción. – mbmcavoy

0

Here is a blog post of mine with an approach using attached behaviors.

se basa en el principio de que los diferentes valores de enumeración no necesitan limitarse a cambiar de cadena. En su lugar, puede declarar qué partes de la interfaz de usuario desea representar cada valor (cadenas, imágenes, diferentes controles y diseños, etc.) y utilizar un comportamiento adjunto para controlar su visibilidad.

Su situación, entonces, se puede enmarcar como si tuviera dos bloques de texto diferentes, cada uno vinculado a la misma propiedad del tipo ExportRegulationType. Al estar sometida a la misma propiedad, sus condiciones de visibilidad son mutuamente excluyentes:

<Grid> 
    <TextBlock 
     Text="EAR" 
     local:EnumVisibility.Value="{Binding ExportRegulationType}" 
     local:EnumVisibility.TargetValue="EAR" 
    /> 
    <TextBlock 
     Text="Do Not Export" 
     local:EnumVisibility.Value="{Binding ExportRegulationType}" 
     local:EnumVisibility.TargetValue="DoNotExport" 
     FontWeight="Bold" 
    /> 
</Grid> 

que incluía el FontWeight="Bold" a demostrar que se puede tomar decisiones diferentes para cada valor de la enumeración. Esto también admite la localización XAML porque el texto se establece como cualquier otro bloque de texto.

Consulte the post para obtener un tutorial completo de la solución, ejemplos de código y un archivo zip que contiene el marco y una aplicación de ejemplo.

Editar en respuesta a la información adicional:

Here is another post in the same series which describes how to select enumeration values with Selector controls.

Un ComboBox con destino a la propiedad ExportRegulationType se vería esta esto:

<ComboBox local:EnumSelector.SelectedValue="{Binding ExportRegulationType, Mode=TwoWay}"> 
    <ComboBoxItem Content="EAR" local:EnumSelector.ItemValue="EAR" /> 
    <ComboBoxItem Content="Do Not Export" local:EnumSelector.ItemValue="DoNotExport" /> 
</ComboBox> 

Asociamos cada elemento con un valor de enumeración, luego use un enlace TwoWay a EnumSelector.SelectedValue para que se vuelva a escribir en el modelo de vista ' s propiedad cada vez que cambie.

Esto proporciona la misma flexibilidad que con los bloques de texto: puede tomar las decisiones que desee sobre cómo configurar el texto y lo que contiene cada elemento.

+0

Interesante idea. En realidad, no aborda las preocupaciones inmediatas, pero puedo ver cómo podría ser útil para ciertas situaciones. – mbmcavoy

+0

@mbmcavoy: su pregunta está formulada en términos de una solución preconcebida (llamada "pidiendo una regla de metal delgado" por Eric Lippert, http://blogs.msdn.com/b/ericlippert/archive/2003/11/03/ a-parable.aspx). Identifiqué y resolví el problema que está tratando de resolver, los nombres de enumeración amistosos, e incorporé su requisito principal, no cruxt en el modelo de vista. Por supuesto, no implica el enlace del diccionario, pero eso no es una restricción inherente de su objetivo subyacente. –

1

Lo resolví con una combinación de lo que @Dylan y @Meleak escribieron. Estoy poniendo esto como una respuesta para mostrar lo que la solución final fue:

En primer lugar, he implementado un IValueConverter, (basado en @ respuesta de Meleak):

class EnumDescriptionConverter : IValueConverter 
{ 

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     Enum regulation = (Enum)value; 
     return GetEnumDescription(regulation); 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     return String.Empty; 
    } 

    /// <summary> 
    /// Returns text intended for display based on the Description Attribute of the enumeration value. 
    /// If no Description Attribute is applied, the value is converted to a string and returned. 
    /// </summary> 
    /// <param name="enumObj">The enumeration value to be converted.</param> 
    /// <returns>Text of the Description Attribute or the Enumeration itself converted to string.</returns> 
    private string GetEnumDescription(Enum enumObj) 
    { 
     // Get the DescriptionAttribute of the enum value. 
     FieldInfo fieldInfo = enumObj.GetType().GetField(enumObj.ToString()); 
     object[] attributeArray = fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false); 

     if (attributeArray.Length == 0) 
     { 
      // If no Description Attribute was found, default to enum value conversion. 
      return enumObj.ToString(); 
     } 
     else 
     { 
      // Get the text of the Description Attribute 
      DescriptionAttribute attrib = attributeArray[0] as DescriptionAttribute; 
      return attrib.Description; 
     } 
    } 
} 

he etiquetado mi enumeración (tenga en cuenta que varios los valores no etiquetados como el texto deseado es el mismo que el valor en sí):

public enum ExportRegulationType 
{ 
    [Description("Not Determined")] 
    NotDetermined, // Export authority not determined 

    EAR,   // Controlled by EAR Regulations 

    ITAR,   // Controlled by ITAR Regulations 

    [Description("Do Not Export")] 
    DoNotExport, // Export not allowed 

    Unrestricted // Export not controlled 
} 

En mi App.xaml, declaré la ObjectDataProvider para obtener la lista de valores de enumeración y la EnumDisplayConverter (Aquí ya que serán utilizado por varias vistas diferentes):

<Application.Resources> 
    [Other stuff...] 
    <ObjectDataProvider MethodName="GetValues" 
         ObjectType="{x:Type sys:Enum}" 
         x:Key="ExportRegulationValues"> 
     <ObjectDataProvider.MethodParameters> 
      <x:Type TypeName="models:ExportRegulationType"/> 
     </ObjectDataProvider.MethodParameters>  
    </ObjectDataProvider> 
    <local:EnumDescriptionConverter x:Key="ExportDisplayConverter"/> 
</Application.Resources> 

Para un TextBlock:

<TextBlock Text="{Binding Export.Regulation, Converter={StaticResource ExportDisplayConverter}}"/> 

para un cuadro combinado:

<ComboBox ItemsSource="{Binding Source={StaticResource ExportRegulationValues}}" 
      SelectedValue="{Binding Document.Export.Regulation}"> 
    <ComboBox.ItemTemplate> 
     <DataTemplate> 
      <TextBlock Text="{Binding Converter={StaticResource ExportDisplayConverter}}"/> 
     </DataTemplate> 
    </ComboBox.ItemTemplate> 
</ComboBox> 

Esto funciona perfectamente !

Cuestiones relacionadas