Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Thomas Lebrun

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

Actualités

[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

- Attention : Arnaque IE7/MSN par .net is good... C# is better ;) le il y a 4 heures et 45 minutes

- Comme Mitsu :-) par Matthieu MEZIL le il y a 7 heures et 7 minutes

- [OpenDocument] Quelques détails sur l’implémentation dans Office 2007 par Julien Chable le il y a 10 heures et 20 minutes

- Page de démarrage CodeS-SourceS par Nix's Blog le 08-07-2008, 19:14

- SharePoint : Erreur pénible lors de la compilation de projet SharePoint - XmlSerializers.dll par Blog Technique de Romelard Fabrice le 08-07-2008, 18:43

- [MOSS Tip Of The Day] Comment connaître le mode de notre page de publication par Nicolas Humann le 08-07-2008, 18:14

- SETI@CodeS-SourceS par Nix's Blog le 08-07-2008, 16:49

- jQuery VS ASP.NET AJAX par Le blog technique de Loïc Bar le 08-07-2008, 15:29

- Lucas change de fonction chez Microsoft France par LucasR le 08-07-2008, 13:02

- Pixel par Blog Technique d'Audrey PETIT le 08-07-2008, 11:25