2010-03-17 5 views
3

En essayant de faire apparaître le contenu d'une liste qui est une propriété de dépendance dans un menu contextuel WPF.Menu contextuel WPF lié à la propriété de dépendance List <>

J'ai une classe avec la propriété de dépendance suivante, une liste des Foo (données classe holding):

public List<Foo> FooList 
    { 
     get { return (List<Foo>)GetValue(FooListProperty); } 
     set { SetValue(FooListProperty, value); } 
    } 
    public static DependencyProperty FooListProperty = 
     DependencyProperty.Register("FooList", typeof(List<Foo>), 
      typeof(FooButton)); 

En XAML, je mis en place la ressource statique suivante, je suppose que son nécessaire depuis le isnt menu contextuel une partie de l'arbre visuel:

<UserControl.Resources> 
    <ResourceDictionary>    
     <CollectionViewSource 
      x:Key="FooListSource" 
      Source="{Binding FooList}"/> 

     <!-- ... --> 

    </ResourceDictionary> 
</UserControl.Resources> 

partie également de la ResourceDictionary ci-dessus est un CompositeCollection qui est nécessaire pour rendre les éléments apparaissent dans le menu contextuel réel. Si la propriété UserControl CanStop est true, nous affichons également un séparateur et une commande d'arrêt. Ces liaisons échouent également, bien que les MenuItems apparaissent eux-mêmes. Donc, si je peux comprendre pourquoi ces échecs, la liste pourrait être plus facile.

<CompositeCollection x:Key="FooListItems"> 
    <CollectionContainer 
     Collection="{Binding Source={StaticResource FooListSource}}"/> 
    <Separator 
     Visibility="{Binding CanStop, 
      Converter={StaticResource VisibleIfTrue}}" /> 
    <MenuItem 
     Command="{x:Static Buttons:FooButton.Stop}" 
     Header="Stop" 
     Visibility="{Binding CanStop, 
      Converter={StaticResource VisibleIfTrue}}"/> 
</CompositeCollection> 

Et enfin le menu contextuel lui-même, également dans le ResourceDictionary:

<ContextMenu 
    x:Key="FooButtonMenu" 
    ItemsSource="{Binding Source={StaticResource FooListItems}}" 
    ItemTemplate="{StaticResource FooListTemplate}" 
    <ContextMenu.CommandBindings> 
     <CommandBinding 
       Command="{x:Static Buttons:FooButton.Stop}" 
       Executed="Stop_Executed" /> 
    </ContextMenu.CommandBindings> 
</ContextMenu> 

Je me sens moyen d'affichage Im à beaucoup de code, mais je ne suis pas sûr que je peux faire cette pièce plus simple. Seul le séparateur et le menuitem codé en dur apparaissent. Donc quelque chose doit être foiré avec les fixations. Les reliures ne sont généralement pas si difficiles mais maintenant quand je veux lier quelque chose qui ne fait pas vraiment partie du même arbre, je me sens un peu perdu.

Toutes les suggestions sont les bienvenues. :)

+0

Comment utilisez-vous FooList DependencyProperty? En particulier, attribuez-vous une liste entièrement remplie à la propriété ou attribuez-vous une liste vide à la propriété, puis remplissez la liste par la suite? DependencyProperty va propager l'affectation à une liste complètement nouvelle, mais si vous voulez surveiller les changements dans la liste, vous devrez utiliser ObservableCollection ou une autre implémentation de INotifyCollectionChanged. –

+0

Une fonction est appelée qui déclenche la lecture de données à partir d'un système hérité, je parcours les données en faisant 'FooList.Ajouter (myNewFoo); '. Êtes-vous en train de dire que je devrais simplement changer le 'List <>' pour un 'ObservableCollection <>'? – Mizipzor

+0

Euh .. tout me semble ok! Pouvez-vous s'il vous plaît télécharger votre projet de démonstration quelque part? Peut-être qu'il vous manque un DataContext? – mg007

Répondre

1

Comme vous le suspectiez, votre problème semble provenir de l'utilisation de List<Foo> au lieu de ObservableCollection<Foo>. Étant donné que List<Foo> n'informe pas sur les modifications apportées aux propriétés, la seule façon de faire en sorte que WPF reconnaisse que vous avez ajouté ou supprimé un élément consiste à définir temporairement la propriété FooList sur autre chose, puis à la rétablir.

Il n'est pas nécessaire de passer à une propriété CLR. Remplacez simplement List<Foo> par ObservableCollection<Foo>.

La raison pour laquelle les liaisons dans votre CompositeCollection ne fonctionnent pas est que CompositeCollection n'est pas un DependencyObject, donc il ne peut pas hériter d'un DataContext.

+0

Existe-t-il une alternative à CompositeCollection que je peux utiliser, c'est un DependencyObject? Bien que les éléments ne sont mis à jour qu'une fois le menu contextuel affiché, et je le faisais de manière simple en code-behind, mais je veux essayer de le faire maintenant. – Mizipzor

+0

Il suffit de permuter List pour ObservableCollection pour que cela fonctionne. – Mizipzor

0

Je ne vois pas pourquoi vous avez fait FooList une propriété de dépendance. Vous n'en faites pas la cible d'une liaison, ce qui est la raison la plus courante de créer une propriété de dépendance. Vous n'avez pas implémenté de rappel, il ne peut donc pas modifier la notification (la deuxième raison la plus courante pour créer une propriété de dépendance). Vous ne l'utilisez pas pour l'héritage de valeur. Alors pourquoi, alors?

Il me semble que ce que vous voulez vraiment, c'est que FooList soit une propriété CLR normale de type ObservableCollection<Foo> (ou n'importe quelle classe qui implémente INotifyCollectionChanged). Cela fera toute la notification de changement dont vous avez besoin - au moins, ce dont vous avez besoin pour le code que vous avez posté jusqu'à présent.

+0

Cela ressemble à un hareng rouge pour moi. Nous pourrions discuter toute la journée pour savoir s'il est approprié de faire de FooList une propriété DependencyProperty ou une propriété CLR. Le fond est que DependencyProperty peut faire tout ce qu'une propriété CLR peut faire et bien plus encore. Bien qu'il puisse être considéré comme un mauvais choix dans certains scénarios (et je ne suis pas sûr que ce soit l'un d'entre eux), il n'est pas lié au problème de mizipzor. –

+0

Vous avez raison de dire que cela n'a pas d'importance si c'est une propriété de dépendance ou non. Ce qui est réellement important, c'est que son type soit une collection qui implémente 'INotifyCollectionChanged'. –

Questions connexes