Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

WPF : Définir une propriété attachée dans un DataTemplate

Je ne sais pas si vous avec déjà essayé de faire ça en XAML mais moi ça fait un petit bout de temps que j'essaye et le viens enfin de trouver comment faire.

Je m'explique : j'ai une classe Personne qui contient 3 propriétés (Nom, Action et Location). C'est un DependencyObject, ce qui permet d'utiliser ses propriés avec WPF (ce ne sont pas de propriétés au sens CLR) pour faire par exemple du DataBinding, des animations, et autres trucs funs de WPF. J'aurais aussi pu utiliser une classe qui implémente INotifyPropertyChanged si j'avais vraiment voulu que ma classe soit totalement indépendante de WPF.

public class Personne : DependencyObject
{
    public static DependencyProperty NomProperty = DependencyProperty.Register("Nom", typeof(
string), typeof(Personne));
    public static DependencyProperty ActionProperty = DependencyProperty.Register("Action", typeof(
string), typeof(Personne));
    public static DependencyProperty LocationProperty = DependencyProperty.Register("Location", typeof(
Vector), typeof(Personne));

   
public Personne(Vector location, string nom, string action)
    {
        SetValue(NomProperty, nom);
        SetValue(ActionProperty, action);
        SetValue(LocationProperty, location);
    }
}

Je crée une collection de Personne, mais plutôt que d'utiliser une liste, j'utilise une ObservableCollection pour pouvoir utiliser le DataBinding avec :

private ObservableCollection<Personne> groupe = new ObservableCollection<Personne>();

Je peuple cette collection :

groupe.Add(new Personne(new Vector(20, 50), "Flavien", "Manger"));
groupe.Add(
new Personne(new Vector(110, 30), "Flavien", "Marcher"));
groupe.Add(
new Personne(new Vector(120, 110), "Manon", "Courrir"));
groupe.Add(
new Personne(new Vector(220, 70), "Manon", "Nager"));

Je souhaiterais maintenant afficher pour chacune des personnes un petit rectangle qui affiche son nom, et un bouton avec l'action a effectuer. Surtout, je voudrais que ce rectangle soit placé à l'emplacement défini par le Vector, comme ça en modifiant un objet Personne (par exemple sa Location), l'affichage est modifié automatiquement.

Je vais donc afficher ces Personne dans un contrôle qui permet de stocker un contenu multiple. Je vais utiliser un ItemsControl, voyez ça comme une ListBox bas de gamme : sans selection, sans défilement, cela permet juste d'avoir un contenu multiple, par opposition au ContentControl qui ne peut avoir qu'un seul élément dans son contenu. La plupart des contrôles WPF dérivent d'un de ces 2 contrôles de base. Je déclare donc un contrôle dans le fichier XAML :

<ItemsControl x:Name ="list"/>

et dans le code source, je dis que je veux que les Items de ce contrôle soient liés à ma collection groupe :

list.ItemsSource = groupe;

Ca signifie que mon ItemsControl a comme contenu des objets Personne, or ces objets n'ont rien définis du tout quand à leur affichage. En effet, quand on lance l'application, on a ça :

En fait, les propriété Content de ContentControl et Items de ItemsControl peuvent contenir absoluement n'importe quoi (ici c'est des Personne). Par contre, WPF ne peut afficher que des strings ou des UIElement. Donc ici WPF "transforme" les Personne en string par la methode ToString(), qui est disponible pour n'importe quel object (c'est le comportement par défaut). Mais si je veux qu'il m'affiche ça en utilisant un UIElement, je dois définir un DataTemplate, pour lui indiquer comment "transformer" une Personne en UIElement :

<ItemsControl x:Name ="list">

  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <Border BorderBrush="BlueViolet" BorderThickness="2" Padding="5,5,5,5">
        <StackPanel>
          <TextBlock Text="{Binding Path=Nom}"/>
          <Button Content="{Binding Path=Action}"/>
        </StackPanel>
      </Border>
    </DataTemplate>
  </ItemsControl.ItemTemplate>

</ItemsControl>


Là, j'obtient un truc comme ça, c'est un peu mieux (mais c'est moche, je sais).

On arrive maintenant sur ce que j'ai eu le plus de mal à trouver. Comment faire pour que ma propriété Location définisse la position du rectangle mauve dans mon canevas ? Le plus logique serait de faire ça :

<ItemsControl x:Name ="list">

  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <Border BorderBrush="BlueViolet" BorderThickness="2" Padding="5,5,5,5"
Canvas.Left="{Binding Path=Location.X}" Canvas.Top="{Binding Path=Location.Y}">
        <StackPanel>
          <TextBlock Text="{Binding Path=Nom}"/>
          <Button Content="{Binding Path=Action}"/>
        </StackPanel>
      </Border>
    </DataTemplate>
  </ItemsControl.ItemTemplate>

</ItemsControl>

mais pas de chance, ça ne marche pas, sûrement du fait que ce sont des propriétés attachées... donc après maintes recherches sur le net, j'ai trouvé comment faire, il faut passer par la propriété ItemsControl.ItemContainerStyle :

<ItemsControl x:Name ="list">

  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <Border BorderBrush="BlueViolet" BorderThickness="2" Padding="5,5,5,5">
        <StackPanel>
          <TextBlock Text="{Binding Path=Nom}"/>
          <Button Content="{Binding Path=Action}"/>
        </StackPanel>
      </Border>
    </DataTemplate>
  </ItemsControl.ItemTemplate>

  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <Canvas/>
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>

  <ItemsControl.ItemContainerStyle>
    <Style>
      <Setter Property="Canvas.Left" Value="{Binding Path=Location.X}"/>
      <Setter Property="Canvas.Top" Value="{Binding Path=Location.Y}"/>
    </Style>
  </ItemsControl.ItemContainerStyle>
     
</ItemsControl>

et là, on obtient bien la chose suivante. Maintenant, je peux diriger mes boites (moches, certes) en modifiant la propriété Location de la Personne correspondante :

En tout cas j'aimerais bien savoir pourquoi la première solution ne marche pas.

Publié jeudi 13 juillet 2006 14:45 par RaptorXP
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Commentaires

# WPF : Les mod&amp;#232;les de contenus et les Templates des contr&amp;#244;les

On ne vas pas s'arr&#233;ter en si bon chemin. Je vais maintenant parler de mod&#232;les de contenu de WPF.
Une...
lundi 24 juillet 2006 16:32 by Code is poetry
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Merci par Blog de Jérémy Jeanson le 10-01-2019, 20:47

- Office 365: Script PowerShell pour auditer l’usage des Office Groups de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 11:02

- Office 365: Script PowerShell pour auditer l’usage de Microsoft Teams de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 10:39

- Office 365: Script PowerShell pour auditer l’usage de OneDrive for Business de votre tenant par Blog Technique de Romelard Fabrice le 04-25-2019, 15:13

- Office 365: Script PowerShell pour auditer l’usage de SharePoint Online de votre tenant par Blog Technique de Romelard Fabrice le 02-27-2019, 13:39

- Office 365: Script PowerShell pour auditer l’usage d’Exchange Online de votre tenant par Blog Technique de Romelard Fabrice le 02-25-2019, 15:07

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Stream Portal par Blog Technique de Romelard Fabrice le 02-21-2019, 17:56

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Video Portal par Blog Technique de Romelard Fabrice le 02-18-2019, 18:56

- Office 365: Script PowerShell pour extraire les Audit Log basés sur des filtres fournis par Blog Technique de Romelard Fabrice le 01-28-2019, 16:13

- SharePoint Online: Script PowerShell pour désactiver l’Option IRM des sites SPO non autorisés par Blog Technique de Romelard Fabrice le 12-14-2018, 13:01