J'ai un ListBox qui présente une liste d'objets par le biais de ItemSource. Étant donné que chaque objet a des besoins d'affichage spéciaux, je définis un ItemTemplateSelector qui renvoie le DataTemplate approprié en fonction de l'objet. Tout cela fonctionne sans accroc.Combinaison de DataTemplates à l'exécution
Les DataTemplates de chaque objet suivent une formule commune, mais contiennent des éléments personnalisés au milieu. Par exemple:
<DataTemplate x:Key="collectibleTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border BorderBrush="LightGray" BorderThickness="1">
<Expander IsExpanded="True" Header="{Binding ComponentName}" Background="WhiteSmoke">
<StackPanel>
<TextBlock Margin="5,5,5,0" Text="{Binding EditDescription}" TextWrapping="Wrap" />
<!-- This is the only custom part of each template -->
<StackPanel Margin="0,10,5,0" Orientation="Horizontal">
<Label Content="Type:" />
<ComboBox Height="22" HorizontalAlignment="Left" SelectedItem="{Binding Path=CollectibleType, Mode=TwoWay}"
ItemsSource="{Binding Source={StaticResource collectibleTypeFromEnum}}" />
</StackPanel>
<!-- End custom part -->
<StackPanel Margin="0,0,0,5">
<Label Content="Available Actions:" >
<Label.Style>
<Style TargetType="Label">
<Setter Property="Visibility" Value="Visible" />
<Style.Triggers>
<DataTrigger Binding="{Binding EditActions.Count}" Value="0">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
<ItemsControl ItemsSource="{Binding EditActions}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Command="{Binding}" Content="{Binding Title}" ToolTip="{Binding ToolTip}" Margin="5,0,5,0"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</StackPanel>
</Expander>
</Border>
</Grid>
</DataTemplate>
Comme vous pouvez le voir il y a beaucoup de XAML partagé, en enveloppant une petite section personnalisée au milieu.
Des modèles de données supplémentaires seront écrits par d'autres ingénieurs (ils voudront en créer un pour chaque nouveau type d'objet qu'ils ajouteront), donc je suis intéressé à faire de la création d'un nouveau DataTemplate infaillible et indolore possible. Pas de copie de l'intégralité de DataTemplate avec le "truc" personnalisé ajouté au milieu, bien sûr - mais je ne suis pas non plus parti pour extraire des parties du modèle comme pièces réutilisables et les référencer parce qu'il conduit encore à beaucoup de code dupliqué chaque nouveau DataTemplate, et cela signifie des erreurs possibles et une maintenabilité difficile. À savoir, ce droit ici est une approche plus maintenable mais se sent encore suboptimale:
<DataTemplate x:Key="collectibleTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border BorderBrush="LightGray" BorderThickness="1">
<Expander IsExpanded="True" Header="{Binding ComponentName}" Background="WhiteSmoke">
<StackPanel>
<TextBlock Margin="5,5,5,0" Text="{Binding EditDescription}" TextWrapping="Wrap" />
<!-- This is the only custom part of each template -->
[...]
<!-- End custom part -->
<ContentPresenter Content="{StaticResource AvailableActions}" />
</StackPanel>
</Expander>
</Border>
</Grid>
</DataTemplate>
<StackPanel Margin="0,0,0,5" x:Key="AvailableActions" x:Shared="false">
<Label Content="Available Actions:" >
<Label.Style>
<!--
[Bottom half of shared XAML from the first example, offloaded here]
-->
</StackPanel>
Alors: quelle est ma meilleure stratégie pour résoudre ce problème? Je suis toujours bloqué avec l'utilisation de DataTemplates parce que c'est le seul élément qu'un ListBox ItemTemplateSelector accepte. Est-il possible de créer un DataTemplate composé dans le DataTemplateSelector? Je fournirais le DataTemplate stock partagé par tous les objets et les références DataTemplateSelector dans le bit de XAML personnalisé requis pour chaque type d'objet. D'autres ingénieurs se connecteraient à ce comportement de code généralisé. Je ne suis pas sûr, tâtonnant un peu dans l'obscurité ici comme s'il y a un modèle qui me permet de résoudre ceci élégamment.
Et, juste pour référence: mon DataTemplateSelector actuel est super simple. C'est là que je m'attendrais à construire le DataTemplate final, plutôt que de simplement en renvoyer un qui soit codé en dur dans XAML.
public class NodeComponentDataTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
FrameworkElement element = container as FrameworkElement;
if (element != null && item != null)
{
if (item is CollectibleComponent)
return element.FindResource("collectibleTemplate") as DataTemplate;
// [...]
}
}
}
J'ai trouvé cette page assez utile après avoir lu plus sur XamlParser. http://www.ikriv.com/dev/wpf/DataTemplateCreation/ – Drakestar
Je suis en train de mettre en œuvre la solution dès maintenant. Juste appris de l'expérience pour ne pas accepter une réponse jusqu'à ce que je suis réellement fait :) (Mais je le ferai.) – Drakestar