2011-03-15 5 views
7

J'ai essayer de construire un contrôle utilisateur qui affiche le contenu d'un dictionnaireC# Générique contrôle utilisateur WPF

le problème est que je ne connais pas les types de la clé et la valeur dans le contrôle de l'utilisateur, i connaîtrait au point où je crée le contrôle de l'utilisateur, mais C# ne semble pas vouloir me laisser créer un contrôle utilisateur générique qui me les laisser passer pour un dictionnaire hébergé

-à-dire

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

parce que il référence un fichier généré dans le fichier. \ Obj \ Debug \ MyCtrl.gics qui est en lecture seule

la seule solution qui se présente à moi est de créer la classe à partir de zéro et de ne pas laisser le concepteur gérer le formatage est-il une meilleure possibilité? Pour donner un peu de contexte dans environ 8-10 endroits dans mon code, j'ai besoin de l'utilisateur pour remplir des dictionnaires de valeurs et au lieu de construire 8-10 contrôles qui font tous exactement la même chose, mais avec des types différents (en fait, un la plupart du temps la seule différence est quelle enum sert de clé) je voulais un seul contrôle pour gérer cela

Répondre

3

Vous pouvez utiliser générique comme si vous n'utilisez pas XAML. Mais si vous voulez utiliser XAML pour définir votre contrôle, vous ne pouvez pas utiliser de générique

+0

La façon dont je prévois de l'ajouter à la XAML est via un contrôle de contenu servant de récipient, je puis instancier le générique dans le code et ajouter au récipient. – MikeT

1

Si vous voulez pouvoir utiliser votre contrôle dans xaml, vous ne pourrez pas créer un UserControl générique comme WPF ne le fait pas ne le supporte pas. Comment déclarer instancié ce type dans xaml?

Je regarderais comment d'autres contrôles géreraient quelque chose comme ça. Par exemple, un ListBox vous permet de remplir une liste d'éléments sans tenir compte du type de collection analysé dans son ItemsSource. Pour vos différents types de dictionnaires, vous pouvez avoir plusieurs DataTemplates pour chaque type de dictionnaire différent et passer à l'aide d'un TemplateSelector.

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

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

Puis 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

Je dois dire qu'il m'a toujours semblé étrange que lorsque MS réécrit .net pour inclure des génériques de type gentil sûr qu'ils n'ont pas décidé d'inclure cela dans leurs concepteurs pour les contrôles. après tout, je suis sûr que je ne suis pas le seul à voir le bonus à avoir des contrôles de type – MikeT

1

Comme mentionné Steyca, vous ne pouvez pas utiliser les médicaments génériques en XAML. Vous pouvez cependant créer votre contrôle utilisateur générique et en déduire des types spécifiques à partir de cette classe générique, que vous pouvez utiliser dans XAML. Cela réduit au moins la duplication de code dans une certaine mesure. En tant que sidenote, les génériques en XAML peuvent être possibles si vous le prenez en charge vous-même, en passant le Type comme valeur d'une propriété. Au moins, je crois que c'est l'intention de this article, mais je n'ai pas encore eu le temps de l'essayer moi-même.

+0

J'ai changé mon focus à la classe Control plutôt que le contrôle UserControl comme tel est instancié avec le support du concepteur XAML. ce qui signifie que je dois planifier tous les graphiques sans être capable de les voir, mais au moins se débarrasse du code généré que je ne peux pas écraser – MikeT

1

Il vaudrait peut-être mieux utiliser MVVM, et mettre tous les types et contraintes génériques sur votre viewmodel, pas sur votre vue.

2

J'ai enfin une bonne réponse.

Je construis le contrôle autour d'un Hashtable qui utilise des objets

puis ajouter une extension à la classe d'objet

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); 
     } 
    } 

puis ajoutez une propriété générique qui appelle l'extension de jeter les objets à un dictionnaire

0

La raison pour laquelle vous souhaitez définir un contrôle utilisateur générique est que vous ne connaissez pas la valeur et la valeur de la clé:

private Dictionary<TKey,TValue> someDictionary; 

les types vont être en avance je crois. Si tel est le cas, puis déclarez votre dictionnaire comme:

private Dictionary<dynamic,dynamic> someDictionary 

puis vous serez en mesure d'ajouter toute clé de type et de valeur pour elle. alors assurez-vous que si vous entrez un int et que vos valeurs sont une chaîne par exemple, suivez toujours ce modèle. Par exemple, le compilateur vous permettra de compiler ce code:

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