2010-08-05 17 views
0

Cette question est fortement liée à cette réponse à « How to reference a generic type in the DataType attribute of a HierarchicalDataTemplate? »Comment référencer une implémentation spécifique d'un type générique dans l'attribut DataType d'un DataTemplate?

J'ai suivi l'idée de base de cette réponse et a créé cette structure de données:

<!-- for DictItemVM<string, Remote.Address> which is a viewmodel for a KeyValuePair<...> --> 
<x:Array Type="{x:Type sys:Type}" 
     x:Key="KVParamsStringToRemoteAddress" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:sys="clr-namespace:System;assembly=mscorlib" 
     xmlns:remote="clr-namespace:Remote" 
     xmlns:mvvm="clr-namespace:MVVM"> 
    <x:Type TypeName="sys:String" /> 
    <mvvm:GenericType BaseType="{x:Type TypeName=remote:Address}"/> 
</x:Array> 

<mvvm:GenericType xmlns:mvvm="clr-namespace:MVVM" 
        BaseType="{x:Type TypeName=mvvm:DictItemVM`2}" 
        InnerTypes="{StaticResource KVParamsStringToRemoteAddress}" 
        x:Key="DictItemVMOfStringToRemoteAddress"/> 

DictItemVM<T,U> est un viewmodel pour une KeyValuePair<...> et est dérivé de BaseVM. BaseVM a une vue DataTemplate, mais j'essaye d'en créer un pour DictItemVM<string, Remote.Address>.
Remote.Address est un type de valeur complexe (stocke les informations Path et Access). Remote.Address a sa propre vue DataTemplate.
Alors maintenant que je le StaticResource « DictItemVMOfStringToRemoteAddress », je veux l'utiliser pour spécifier un DataTemplate:

<DataTemplate x:Key="TestKey" DataType="{StaticResource DictItemVMOfStringToRemoteAddress}"> 
    <StackPanel> 
     <Label Content="UniqueName" /> 
     <TextBox Text="{Binding UniqueName}" /> 
     <Label Content="Key"/> 
     <TextBox Text="{Binding Key, Mode=OneWay}" IsEnabled="False" /> 
     <Label Content="Value"/> 
     <ContentControl Content="{Binding Value, Mode=OneWay}" /> 
    </StackPanel> 
</DataTemplate> 

Maintenant, ce DataTemplate doit être utilisé comme point de vue, mais la vue pour BaseVM est en cours de affiché.
Quelqu'un me donne un indice sur celui-ci?

[modifier]: 2010-08-09
Quelques choses que j'essayé:

En x: définition Array J'ai remplacé
<mvvm:GenericType BaseType="{x:Type TypeName=remote:Address}"/>
avec
<x:Type TypeName="remote:Address"/>,
parce que ce qu'il est fondamentalement - aucune différence.

a également essayé de créer le DataType entre les balises (au lieu de se lier à un StaticResource) comme ceci:

<DataTemplate x:Key="TestKey"> 
    <DataTemplate.DataType> 
     <Binding> 
      <Binding.Source> 
       <mvvm:GenericType 
        BaseType="{x:Type TypeName=mvvm:DictItemVM`2}"> 
        <mvvm:GenericType.InnerTypes> 
         <x:Type TypeName="sys:String" /> 
         <x:Type TypeName="remote:Address"/> 
        </mvvm:GenericType.InnerTypes> 
       </mvvm:GenericType> 
      </Binding.Source> 
     </Binding> 
    </DataTemplate.DataType> 

Essayé avec et sans x: Array dans les GenericType.InnerTypes, les deux me donner this Erreur.

Tentative de passage du type d'une propriété statique comme ceci:
DataType="{x:Static mvvm:StaticTypes.DictItemVMOfStringToRemoteAddress}"
et comme ceci:
DataType="{Binding Path={x:Static mvvm:StaticTypes.DictItemVMOfStringToRemoteAddress}}"
Aucune différence. Assez étrangement, ce DataTemplate spécifique doit avoir une valeur de x:Key, contrairement à tous les autres dans le fichier de ressources xaml qui pointent tous vers un type normal, par exemple DataType="{x:Type mvvm:EffectVM}". Si je supprime la clé x:, j'obtiens l'erreur this.

Répondre

1

J'ai trouvé une solution, bien que cette solution ne soit pas vraiment satisfaisante.

En XAML, créez un DataTemplate pour chaque type de KeyValuePair<T,U> que vous souhaitez afficher et de lui donner quelques x uniques: Key:

<DataTemplate x:Key="DictItemOfStringAndAddressVM"> 
    <!-- ... --> 
</DataTemplate> 

Puis, en codebehind, créez un DataTemplateSelector et substituez SelectTemplate:

public class GenericDataTemplateSelector : System.Windows.Controls.DataTemplateSelector 
{ 
    public override System.Windows.DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container) 
    { 
     FrameworkElement element = container as FrameworkElement; 

     if ((element != null) && (item != null)) 
     { 
      if (item is DictItemVM<string, Remote.Address>) 
      { 
       return element.FindResource("DictItemOfStringAndAddressVM") as DataTemplate; 
      } 
      else if(item is SomeOtherComplexType) 
      { 
       // ... 
      } 
      else return base.SelectTemplate(item, container); 
     } 
     return null; 
    } 
} 

Encore une fois en XAML, déclarer cette classe comme ressource:

<mvvm:GenericDataTemplateSelector x:Key="GenDataTempSelect"/> 

Enfin, (dans mon cas) dans le ContentControl, ajoutez la propriété:

ContentTemplateSelector="{StaticResource GenDataTempSelect}" 

-

Inconvénients:

  • Lors de la création d'une nouvelle DataTemplate vous devez modifier le code à deux endroits .
  • Chaque ContentControl, ListView, ... doit définir sa propriété appropriée.
  • Ne répond pas vraiment à la question de savoir comment référencer les types génériques dans WPF!

Avantages:

  • facile d'ajouter de nouveaux types de toute structure ou la complexité (profiter de tous les avantages C# a plus WPF ...)
  • Pas de description de type imbriqué complexe dans WPF, comme la solution ci-dessus nécessiterait.