10 votes

WPF : Liaison dynamique d'une liste à (certaines) des propriétés d'un objet

J'ai une collection d'objets stockés dans un CollectionViewSource et liés à un DataGrid. Je veux afficher une 'vue détaillée' de l'objet actuellement sélectionné dans le DataGrid. Je peux obtenir l'objet actuel en utilisant CollectionViewSource.View.CurrentItem.

MyClass
{
    [IsImportant]   
    AProperty{}

    AnotherProperty{}

    [IsImportant]
    YetAnotherProperty{}
}

Ce que je voudrais faire, c'est afficher un libellé (avec le nom de la propriété) et un contrôle (pour l'édition) dans une liste, pour chacune de ces propriétés marquées avec l'attribut IsImportant. La liaison doit fonctionner entre les modifications apportées, le DataGrid et l'objet de sauvegarde. Le contrôle affiché doit varier en fonction du type de propriété, qui peut être soit boolean, string ou IEnumerable (j'ai écrit un IValueConverter pour convertir entre énumérable et chaîne séparée par des sauts de ligne).

Est-ce que quelqu'un sait comment accomplir cela ? Je peux actuellement afficher les valeurs de chaque propriété à travers le code suivant, mais les modifier ne mettrait pas à jour l'objet de sauvegarde :

listBox.ItemsSource = from p in typeof(MyClass).GetProperties()
                      where p.IsDefined(typeof(IsImportant), false)
                      select p.GetValue(_collectionViewSource.View.CurrentItem, null);

Pour clarifier, je voudrais que cela se fasse 'automagiquement', sans spécifier manuellement les noms de propriétés dans le XAML. Si je peux ajouter dynamiquement au XAML au moment de l'exécution en fonction des propriétés marquées d'attributs, cela serait également bien.

13voto

Quartermeister Points 24729

Vous voulez un contrôle qui a une étiquette avec le nom de la propriété et un contrôle pour éditer la valeur de la propriété, alors commencez par créer une classe qui encapsule une propriété d'un objet spécifique pour agir comme le DataContext pour ce contrôle:

public class PropertyValue
{
    private PropertyInfo propertyInfo;
    private object baseObject;

    public PropertyValue(PropertyInfo propertyInfo, object baseObject)
    {
        this.propertyInfo = propertyInfo;
        this.baseObject = baseObject;
    }

    public string Name { get { return propertyInfo.Name; } }

    public Type PropertyType { get { return propertyInfo.PropertyType; } }

    public object Value
    {
        get { return propertyInfo.GetValue(baseObject, null); }
        set { propertyInfo.SetValue(baseObject, value, null); }
    }
}

Vous voulez lier l'ItemsSource d'un ListBox à un objet pour le remplir avec ces contrôles, alors créez un IValueConverter qui convertira un objet en une liste d'objets PropertyValue pour ses propriétés importantes:

public class PropertyValueConverter
    : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return
            from p in value.GetType().GetProperties()
            where p.IsDefined(typeof(IsImportant), false)
            select new PropertyValue(p, value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Binding.DoNothing;
    }
}

Le dernier truc est que vous voulez que le contrôle d'édition varie en fonction du type de propriété. Vous pouvez le faire en utilisant un ContentControl et en définissant le ContentTemplate sur l'un des différents templates d'éditeur basés sur le type de propriété. Cet exemple utilise une case à cocher si la propriété est un booléen et un champ de texte sinon:

    <Setter Property="ContentTemplate" Value="{StaticResource TextBoxTemplate}"/>
    <Style.Triggers>
        <DataTrigger Binding="{Binding PropertyType}" Value="{x:Type sys:Boolean}">
            <Setter Property="ContentTemplate" Value="{StaticResource CheckBoxTemplate}"/>
        </DataTrigger>
    </Style.Triggers>

Ensuite, vous pouvez simplement créer votre ListBox comme:

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X