2011-03-15 21 views
7

He tratando de construir un control de usuario que mostrará el contenido de un diccionariousuario C# genérico de control de WPF

el problema es que no sé los tipos de la clave y el valor en el control del usuario, i sabrían en el punto i crear el control de usuario pero C# no parece querer me deja crear un control de usuario genérico que me permitiera pasar en un diccionario alojado

es decir

public class MyCtrl<TKey,TValue> : UserControl 
{ 
    private Dictionary<TKey,TValue> 
} 

porque hace referencia a un archivo generado en. \ Obj \ Debug \ MyCtrl.gics que es de solo lectura

la única solución que se me presenta es crear la clase desde cero y no dejar que el diseñador maneje ninguno de los formatos ¿hay una mejor posibilidad?

para dar un poco de antecedentes en aproximadamente 8-10 lugares en mi código, necesito que el usuario complete diccionarios de valores y en lugar de construir 8-10 controles que hacen exactamente lo mismo pero con diferentes tipos (de hecho, la mayoría de las veces la única diferencia es qué enum está sirviendo como clave). Yo quería un solo control para manejar esto.

Respuesta

3

Puede usar genérico como si no usara XAML. Pero si desea usar XAML para definir su control, no puede usar el genérico

+0

La forma en que estoy planeando para añadirlo a la XAML es a través de un control de contenido que actúa como un contenedor, i entonces una instancia del genérico en el código y añadir al contenedor. – MikeT

1

Si desea poder usar su control en xaml, no podrá crear un UserControl genérico de esta manera ya que WPF simplemente no lo hace no lo soporto ¿Cómo podrías instanciar declarativamente ese tipo en xaml?

Me gustaría ver cómo otros controles manejarían algo como esto. Por ejemplo, un ListBox le permite completar una lista de elementos sin tener en cuenta el tipo de colección analizada en su ItemsSource.

<ListBox ItemsSource="{Binding DictionaryItems}" > 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
     <StackPanel Orientation="Horizontal"> 
      <TextBlock Text="{Binding Key}" /> 
      <TextBlock Text="{Binding Value}" /> 
     </StackPanel> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

Para sus diversos tipos de diccionario podría tener múltiples DataTemplates para cada tipo de diccionario diferente y cambiar utilizando un TemplateSelector.

public class SomeSelector : DataTemplateSelector 
{ 
    public DataTemplate Template1 { get; set; } 
    public DataTemplate Template2 { get; set; } 

    public override DataTemplate SelectTemplate(object item, DependencyObject container) 
    { 
     if (item is IDictionary<string, int>) 
     { 
     return Template1; 
     } 

     return Template2; 
    } 
} 

Luego, en xaml

<UserControl.Resources> 
    <DataTemplate x:Key="Template1"> 
     <StackPanel Orientation="Horizontal"> 
     <TextBlock Text="{Binding Key}" /> 
     <TextBlock Text="{Binding Value}" /> 
     </StackPanel> 
    </DataTemplate> 

    <DataTemplate x:Key="Template2> 
     <StackPanel Orientation="Vertical"> 
     <TextBlock Text="{Binding Key}" /> 
     <TextBlock Text="{Binding Value}" /> 
     </StackPanel> 
    </DataTemplate> 

    <SomeSelector x:Key="SomeSelector" Template1="{StaticResource Template1}" Template2="{StaticResource Template2}" /> 
</UserControl.Resources> 

<ListBox ItemsSource="{Binding DictionaryItems}" ItemTemplateSelector="{StaticResource SomeSelector}" /> 
+3

Tengo que decir que siempre me ha llamado la atención que cuando MS reescribió .net para incluir tipos genéricos genéricos seguros que no decidieron incluir en sus diseñadores para controles. después de todo, estoy seguro de que no soy el único que puede ver la bonificación de tener controles de tipo seguro – MikeT

1

Como se mencionó Steyca, no puede utilizar los genéricos en XAML. Sin embargo, puede crear su control de usuario genérico y derivar tipos específicos de esta clase genérica, que puede usar en XAML. Esto al menos reduce la duplicación de código hasta cierto punto.

Como nota al margen, los genéricos en XAML podrían ser posibles si lo admite usted mismo, pasando el Tipo como el valor de una propiedad. Al menos, creo que esa es la intención de this article, pero aún no tuve tiempo de probarlo yo mismo.

+0

Cambié mi enfoque a la clase de Control en lugar de que el UserControl como se crea una instancia sin soporte de diseñador así que vuelca XAML. lo que significa que tengo que planificar todos los gráficos sin poder verlos, pero al menos me deshago del código generado que no puedo sobrescribir – MikeT

1

Puede ser mejor que use MVVM y ponga todos los tipos genéricos y restricciones en su modelo de vista, no en su vista.

2

Finalmente tengo una respuesta funcional.

que generar el control alrededor de una tabla hash que utiliza objetos

a continuación, añadir una extensión a la clase de objeto

public static bool TryParse<TType>(this object obj, out TType result) 
    { 
     try 
     { 
      result = (TType)Convert.ChangeType(obj, typeof(TType)); 
      return true; 
     } 
     catch 
     { 
      result = default(TType); 
      return false; 
     } 
    } 
    public static TType Parse<TType>(this object obj) where TType : struct 
    { 
     try 
     { 
      return (TType)Convert.ChangeType(obj, typeof(TType)); 
     } 
     catch 
     { 
      throw new InvalidCastException("Cant cast object to " + typeof(TType).Name); 
     } 
    } 

a continuación, añadir una propiedad genérica que llama a la extensión a emitir los objetos a un diccionario

0

La razón por la que desea establecer un control de usuario genérico es porque no sabe en qué la clave y el valor está:

private Dictionary<TKey,TValue> someDictionary; 

tipos van a ser de antemano, creo. Si ese es el caso, entonces declarar su diccionario como:

private Dictionary<dynamic,dynamic> someDictionary 

entonces usted será capaz de añadir cualquier tipo de clave y valor a la misma. así que asegúrese de que si su clave es un int y sus valores son una cadena, por ejemplo, siempre siga ese patrón. Por ejemplo, el compilador le permitirá compilar este código:

 Dictionary<dynamic, dynamic> myDictionAry = new Dictionary<dynamic, dynamic>(); 
     myDictionAry.Add(1, "kd"); 
     myDictionAry.Add("kjdf", 3); 
Cuestiones relacionadas