Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Thomas Lebrun

Tout sur WPF, LINQ, C# et .NET en général !

[WPF] Comment récupérer la valeur d'un attribut personnalisé lors du DataBinding ?

J'ai répondu récemment à une question, sur les forums de Developpez.com, qui était forte intéressante et qui valait bien un petit post sur mon blog.

Pour faire simple, le demandeur était dans le cas suivant:

  • Une listbox liée à une liste de personne
  • Un attribut personnalisé sur les propriétés de la classe Person

Son besoin était simple: il voulait pouvoir afficher, lors d'un binding, la valeur d'une des propriétés de l'attribut personnalisé. En terme de code, nous avions donc ceci:

public class Person

{

    [PersonProperties("LastName : ")]

    public string LastName { get; set; }

 

    [PersonProperties("FirstName : ")]

    public string FirstName { get; set; }

}

 

public class PersonCollection : ObservableCollection<Person>

{

}

 

[global::System.AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = true)]

sealed class PersonPropertiesAttribute : Attribute

{

    public string Header { get; private set; }

 

    public PersonPropertiesAttribute(string header)

    {

        this.Header = header;

    }

}

Il faut à présent remplir notre collection de personne, par exemple lors du chargement de la fenêtre:

private void Window_Loaded(object sender, RoutedEventArgs e)

{

    ObjectDataProvider odp = this.TryFindResource("PersonCollectionDS") as ObjectDataProvider;

 

    if (odp != null)

    {

        PersonCollection pc = odp.Data as PersonCollection;

 

        if (pc != null)

        {

            pc.Add(new Person() { LastName = "LEBRUN", FirstName = "Thomas" });

            pc.Add(new Person() { LastName = "SANTIN", FirstName = "Florent" });

            pc.Add(new Person() { LastName = "SENTENAC", FirstName = "Philippe" });

            pc.Add(new Person() { LastName = "FURUTA", FirstName = "Mitsuru" });

        }

    }

}

Maintenant, il faut faire en sorte que, lors du binding, on arrive à accéder à l'attribut "PersonProperties" (et à sa valeur) et à l'afficher. Pour cela, il faut déjà mettre en place le binding, en utilisant un convertisseur auquel on va passer un paramètre:

<TextBlock HorizontalAlignment="Right" Margin="0,17,8,0" VerticalAlignment="Top" Width="126" Height="16" Text="{Binding Path=SelectedItem, Converter={StaticResource GetPersonAttributeConverter}, ConverterParameter=LastName, ElementName=lbPersons, Mode=Default}" TextWrapping="Wrap" x:Name="tbLastName"/>

<TextBlock HorizontalAlignment="Right" Margin="0,52,8,0" VerticalAlignment="Top" Width="126" Height="16" Text="{Binding Path=SelectedItem, Converter={StaticResource GetPersonAttributeConverter}, ConverterParameter=FirstName, ElementName=lbPersons, Mode=Default}" TextWrapping="Wrap" x:Name="tbFirstName"/>

Comme vous pouvez en douter, toute la magie va se passer dans le convertisseur, qui va tout simplement faire un peu de reflection sur l'objet passé en paramètre (un objet de type Person) et accéder aux attributs personnalisés:

public class GetPersonAttributeConverter : IValueConverter

{

    #region IValueConverter Members

 

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

    {

        string result = string.Empty;

 

        if (value != null)

        {

            Person p = value as Person;

 

            if (p != null)

            {

                var properties = p.GetType().GetProperties();

 

                foreach (var propertyInfo in properties)

                {

                    var attributes = propertyInfo.GetCustomAttributes(typeof(PersonPropertiesAttribute), true);

 

                    if (((PersonPropertiesAttribute)attributes.GetValue(0)) != null)

                    {

                        string header = ((PersonPropertiesAttribute)attributes.GetValue(0)).Header;

 

                        string parameterToUse = parameter as string;

 

                        if (parameterToUse != null)

                        {

                            if (header.Contains(parameterToUse))

                            {

                                switch (parameterToUse)

                                {

                                    case "LastName":

                                        result = string.Concat(header, p.LastName);

                                    break;

 

                                    case "FirstName":

                                        result = string.Concat(header, p.FirstName);

                                        break;

 

                                    default:

                                        break;

                                }

                            }

                        }

                    }

                }

            }

        }

 

        return result;

    }

 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

    {

        return null;

    }

 

    #endregion

}

A l'exécution, le biding est bien mis en place et grâce à la reflection, nous accédons à la valeur des propriétés de notre attribut personnalisé:

image

Pour ceux qui veulent tester, vous trouverez le code source de la démonstration ici: Source

 

A+

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 :
Posted: mardi 29 avril 2008 10:50 par Thomas LEBRUN
Classé sous : , ,

Commentaires

Frédéric Hamel a dit :

Hello Thomas, merci pour ce post c'est tres intéressant.

Le code du converter pourrait être simplifié :

if (value == null || parameter == null)

  return string.Empty;

var property =

value.GetType().GetProperty(parameter.ToString());

var attribute =

property.GetCustomAttributes(

typeof(PersonPropertiesAttribute), false)[0] as PersonPropertiesAttribute;

return string.Concat(

attribute.Header,property.GetValue(value, null));

voila j'espère que ça aidera :)

# avril 29, 2008 15:56

Thomas LEBRUN a dit :

Merci :)

# avril 29, 2008 18:28
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- [Perso] Découvertes estivales : Linux (Part I) par Le blog de FremyCompany le il y a 1 heure et 38 minutes

- [Refactoring] ReSharper pour Visual Studio 2010 (Preview) par Thomas Jaskula le il y a 16 heures et 14 minutes

- [Refactoring] Analyser vos exceptions avec ReSharper Exceptional par Thomas Jaskula le il y a 17 heures et 28 minutes

- SharePoint 2007 : patterns & practices SharePoint Guidance par Philippe Sentenac [MVP SharePoint] le 07-03-2009, 09:56

- [Visual Studio 2010] Les tests cases c’est bien, mais je vais devoir tout réécrire ? par Etienne Margraff le 07-03-2009, 09:00

- MVP[Gribouillon].AddYear par The Grib's Lair [Sébastien PICAMELOT - MVP SharePoint] le 07-03-2009, 08:45

- Clinique INSIA - Projet de fin d’Etudes (Silverlight 3 MVVM et OutOfBrowser, WCF, TFS) - Part 1 par David REI le 07-02-2009, 23:38

- C’est la crise ? Bah pourquoi cramer du budget pub alors ? par Nix's Blog le 07-02-2009, 15:31

- Soyons MVP ! par TheSaib .NET blog le 07-02-2009, 12:15

- SharePoint : Gestion des Erreurs 6398, 7076 et 6482 par Blog Technique de Romelard Fabrice le 07-02-2009, 11:53