WPF - Binding List to UI - Un petit résumé rapide mais utile

Nous pouvons voir partout de nombreux exemples expliquant comment binder une liste d'éléments vers une interface xaml de notre application, voici en passant, un résumé reprennant les différentes étapes pour mettre en place ce genre de binding.

Que Binder ?

Techniquement, vous pouvez binder n'importe quelle type de liste, que ce soit une List<Generique>, un tableau, une ArrayList, tout passera, cependant, vous vous rendrez vitte compte que seul les ObservableCollection<> offrent un support pré-intégré pour l'update du binding lors de l'ajout ou du retrait d'un élément de la collection.

Donc, à mon avis, quitte à avoir parfois besoin d'ObservableCollection, hors mit autre contrainte, autant toujours les utiliser.

Ou binder ?

La class ItemsControl est la class de base des conteneur de list de n'importe d'item. De cette class dérive tout ce qui est Menu, ListBox, ComboBox, TreeView, ...
Tout ce qui est customisable sur un  ItemControl est donc aussi customisable sur un de ses dérivé.

Binder une liste se fait des deux coté de notre interface, premièrement dans les déclaration xaml, ensuite dans le code behind.

Prennon un exemple simple, une liste d'employés :

  1. Creation de notre class d'exemple
    [code:c#]
    class Employee
    {
        private string _nom;
        public string Nom
        {
            get { return _nom; }
            set { _nom = value; }
        }

        private string _prenom;
        public string Prenom
        {
            get { return _prenom; }
            set { _prenom = value; }
        }

        private int _age;
        public int Age
        {
            get { return _age; }
            set { _age = value; }
        }
    }
    [/code]
  2. Création de notre ObservableCollection dans le code behind de notre application
    [code:c#]
    public Window1()
    {
        InitializeComponent();
  3.     ObservableCollection<Employee> list = new ObservableCollection<Employee>()
        {
            new Employee() { Prenom = "Simon", Nom = "Boigelot", Age=22 },
            new Employee() { Prenom = "Loïc", Nom = "Bar", Age=19 },
            new Employee() { Prenom = "Thieu", Nom = "Lizin", Age=21 }
        };
    }
    [/code]

  • Creation de notre ItemControl dans les déclaration xaml
    [code:xml]
    <Window x:Class="SimpleBinding.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">
        <Grid>

            <ItemsControl Name="myItemControl"/>


        </Grid>
    </Window>
    [/code]

    Nous avons maintenant une liste, un endroit ou l'afficher, mais il manque encore un lien entre les deux.

    Ce lien se fait à partir de la propriété ItemSource de notre ItemsControl.

    Définir l'ItemSource dans le code behind

    Par exemple, nous pouvons simplement lier notre liste à notre ItemsControl dans le code behind :

    [code:c#]
    myItemControl.ItemsSource = list;
    [/code]

    Le résultat sera directement visible :
    image

    Définir l'ItemSource dans les définition xaml

    Malheureusement, bien que la solution précédente pour lier notre list à l'interface semble fonctionner, ce n'est pas celle qui sera retenue car elle ne respecte pas du tout la séparation entre le code et l'interface.

    Imaginons, par exemple, vouloir retrouver cette liste à deux endroits différents de l'interface, dans ce dernier cas, il faudrait revenir dans le code behind et ajouter une ligne, ect.

    La meilleur méthode pour binder une liste à une interface est de passer par un ObjectDataProvider :

    1. Changer notre xaml pour y intégrer notre ObjectDateProvider
      [code:xml]
      <Window x:Class="SimpleBinding.Window1"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          Title="Window1" Height="300" Width="300">
          <Window.Resources>
              <ObjectDataProvider x:Key="myEmployeeList"/>
          </Window.Resources>
          <Grid>
              <ItemsControl Name="myItemControl">
                  <ItemsControl.ItemsSource>
                      <Binding Source="{StaticResource myEmployeeList}"/>
                  </ItemsControl.ItemsSource>
              </ItemsControl>
          </Grid>
      </Window>
      [/code]
    2. Changer notre code behind pour lier notre list à notre ObjectDataProvider
      [code:c#]
      public Window1()
      {
          //init + create list

          ObjectDataProvider odp = this.FindResource("myEmployeeList") as ObjectDataProvider;
          odp.ObjectInstance = list;
      }
      [/code]

    Le résultat est exactement le même que dans le dernier exemple, mais nous passons par un intermédiaire suppléméntaire qui assure la séparation du code.

    Comment rendre le tout lisible ?

    Par defaut, le binding utilise la méthode ToString() des objects que vous lui donner.

    ToString()

    Une première méthode pour rendre votre binding lisible est donc simplement d'overrider cette méthode :

    [code:c#]
    public class Employee
    {

        //properties...

        public override string ToString()
        {
            return Nom + " " + Prenom + " (" + Age + ")";
        }
    }
    [/code]

    Résultat:
    image

    Mwai, mais encore une foi, comme toute première méthode, elle ne respecte pas la séparation du code, qui plus est, si l'on désire afficher différement des employés à un endroit de l'interface et à un autre... ca coince.

    Cette méthode ne sera jamais utilisée comme méthode d'affichage définitive, mais elle peut avoir son utilité lors du developement.

    DataTemplate

    Voici la façon la plus belle de rendre lisible tout notre brol. Un DataTemplate est une structure xaml qui sera appliquée à chacun des items de notre ItemsControl.

    Ici le changement ne se fait que dans le code xaml, l'idépendance avec le code behind est parfaite !

    [code:xml]
    <Window x:Class="SimpleBinding.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">
        <Window.Resources>
            <ObjectDataProvider x:Key="myEmployeeList"/>


            <DataTemplate x:Key="EmployeeDataTemplate">
                <Border CornerRadius="5" Margin="3"
                        BorderBrush="Black" BorderThickness="1">
                    <WrapPanel>
                        <Label Content="{Binding Path=Nom}"/>
                        <Label Content="{Binding Path=Prenom}"/>
                        <Label Content="{Binding Path=Age}"/>
                    </WrapPanel>
                </Border>
            </DataTemplate>
        </Window.Resources>
        <Grid>


            <ItemsControl Name="myItemControl"
                          ItemTemplate="{StaticResource EmployeeDataTemplate}">
                <ItemsControl.ItemsSource>
                    <Binding Source="{StaticResource myEmployeeList}"/>
                </ItemsControl.ItemsSource>
            </ItemsControl>


        </Grid>
    </Window>
    [/code]

    Résultat:
    image

    Conclusion

    Voilà, vous avez binder correctement votre liste d'objet, du moins pour ce qui est de l'affichage. Il nous faudra parler de la modification dans un futur proche.

    Quelques autres post pourons vous être utiles :

  • Posted on 08/11/2007 15:17:00 by Togis

    Permalink | Commentaires (0) | Post RSSRSS comment feed |

    Categories: WPF | Binding

    Tags:

    Actuellement noté 2.0 par 4 personne(s)

    • Currently 2/5 Stars.
    • 1
    • 2
    • 3
    • 4
    • 5

    Billets liés

    Ajouter un commentaire


    (Affichera votre icône Gravatar)  

      Country flag





    Live preview

    août 20. 2008 15:55