Comment définir CommandTarget pour MenuItem à l'intérieur d'un ContextMenu?
(Cette question est liée à un autre, mais assez différent, je pense qu'il garantit le placement ici.)
Voici un (très ciselée) Window
:
<Window x:Class="Gmd.TimeTracker2.TimeTrackerMainForm"
xmlns:local="clr-namespace:Gmd.TimeTracker2"
xmlns:localcommands="clr-namespace:Gmd.TimeTracker2.Commands"
x:Name="This"
DataContext="{Binding ElementName=This}">
<Window.CommandBindings>
<CommandBinding Command="localcommands:TaskCommands.ViewTaskProperties"
Executed="HandleViewTaskProperties"
CanExecute="CanViewTaskPropertiesExecute" />
</Window.CommandBindings>
<DockPanel>
<!-- snip stuff -->
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- snip more stuff -->
<Button Content="_Create a new task" Grid.Row="1" x:Name="btnAddTask" Click="HandleNewTaskClick" />
</Grid>
</DockPanel>
</Window>
et voici un (très ciselée) UserControl
:
<UserControl x:Class="Gmd.TimeTracker2.TaskStopwatchControl"
xmlns:local="clr-namespace:Gmd.TimeTracker2"
xmlns:localcommands="clr-namespace:Gmd.TimeTracker2.Commands"
x:Name="This"
DataContext="{Binding ElementName=This}">
<UserControl.ContextMenu>
<ContextMenu>
<MenuItem x:Name="mnuProperties" Header="_Properties" Command="{x:Static localcommands:TaskCommands.ViewTaskProperties}"
CommandTarget="What goes here?" />
</ContextMenu>
</UserControl.ContextMenu>
<StackPanel>
<TextBlock MaxWidth="100" Text="{Binding Task.TaskName, Mode=TwoWay}" TextWrapping="WrapWithOverflow" TextAlignment="Center" />
<TextBlock Text="{Binding Path=ElapsedTime}" TextAlignment="Center" />
<Button Content="{Binding Path=IsRunning, Converter={StaticResource boolToString}, ConverterParameter='Stop Start'}" Click="HandleStartStopClicked" />
</StackPanel>
</UserControl>
Au travers de différentes techniques, un UserControl
peuvent être ajoutées dynamiquement à la Window
. Peut-être via le Bouton dans la fenêtre. Peut-être, de façon plus problématique, à partir d'un stockage de sauvegarde persistant lorsque l'application est démarrée.
Comme on peut le voir à partir du xaml, j'ai décidé qu'il fait sens pour moi d'essayer d'utiliser les Commandes comme un moyen de gérer les différentes opérations que l'utilisateur peut effectuer avec Task
s. Je fais cela avec l'objectif final de l'affacturage toute logique de commande dans un plus formellement définis Contrôleur de couche, mais je suis en train de revoir une étape à la fois.
Le problème que je rencontre est lié à l'interaction entre la commande dans le UserControl
's ContextMenu
et la commande du CanExecute
, défini dans la Fenêtre. Lorsque l'application démarre pour la première fois et les Tâches enregistrées sont restaurés dans TaskStopwatches sur la Fenêtre, qu'aucun des éléments de l'INTERFACE sont sélectionnés. Si je puis immédiatement r-cliquez sur un UserControl
dans le Window
dans une tentative d'exécution de la ViewTaskProperties
de commande, le CanExecute
gestionnaire ne s'exécute et l'élément de menu reste désactivé. Si je puis cliquez sur certains élément de l'INTERFACE utilisateur (par exemple, le bouton) juste pour donner quelque chose de l'accent, la CanExecute
les gestionnaires sont à la CanExecuteRoutedEventArgs
's de la Source de jeu de propriétés de l'élément d'INTERFACE utilisateur qui a le focus.
Dans une certaine mesure, ce problème semble être connu-j'ai appris que les menus de l'itinéraire de la manifestation par le dernier élément qui a le focus pour éviter de toujours envoyer l'événement à partir de l'élément de menu. Ce que je voudrais, cependant, est la source de l'événement le contrôle de lui-même, ou de la Tâche que le contrôle est d'habillage sur elle-même (mais Task
n'est pas un Élément, donc je ne pense pas qu'elle peut être une source).
J'ai pensé que peut-être j'ai été absent de la CommandTarget
bien sur la MenuItem
dans le UserControl
, et ma première pensée a été que j'ai voulu la commande provenant de l'objet UserControl, c'est donc naturellement que j'ai d'abord essayé:
<MenuItem x:Name="mnuProperties"
Header="_Properties"
Command="{x:Static localcommands:TaskCommands.ViewTaskProperties}"
CommandTarget="{Binding ElementName=This}" />
Cet échec comme une défaillance de la liaison. Je ne sais pas pourquoi. Puis j'ai pensé, "Hmmm, je suis à la recherche de l'arbre, alors peut-être ce dont j'ai besoin est un RelativeSource" et j'ai essayé ceci:
<MenuItem x:Name="mnuProperties"
Header="_Properties"
Command="{x:Static localcommands:TaskCommands.ViewTaskProperties}"
CommandTarget="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:TaskStopwatchControl}}}" />
Qui a également échoué, mais quand j'ai regardé mon code xaml de nouveau, j'ai réalisé que la ContextMenu
est dans une propriété de l'objet UserControl, ce n'est pas un élément enfant. J'ai donc deviné (et à ce stade, c'est une supposition):
<MenuItem x:Name="mnuProperties"
Header="_Properties"
Command="{x:Static localcommands:TaskCommands.ViewTaskProperties}"
CommandTarget="{Binding RelativeSource={x:Static RelativeSource.Self}}" />
Et qui a aussi échoué.
Un échec de deviner et vérifier comme c'est assez pour me faire marche arrière et de réaliser que je suis absent une sorte de concept fondamental ici, cependant. Alors, que dois-je faire?
- Est ma compréhension re: le rôle de
CommandTarget
correct en ce que cela permet de modifier le code source d'une commande? - Comment puis-je lier à partir d'un
MenuItem
dansUserControl.ContextMenu
à la possession d'UserControl
? Ou suis-je en train de faire quelque chose de mal, tout simplement parce que je perçois un besoin? - Est mon désir d'avoir le contexte d'une commande définie par l'élément qui a été cliqué pour générer le menu contextuel, par opposition à l'élément qui a le focus avant le menu contextuel, incorrect? Peut-être que j'ai besoin d'écrire ma propre commande au lieu de l'aide de l'
RoutedUICommand
:private static RoutedUICommand viewTaskPropertiesCommand = new RoutedUICommand("View a task's details.", "ViewTaskProperties", typeof(TaskCommands)); public static RoutedUICommand ViewTaskProperties { get { return viewTaskPropertiesCommand; } }
- Est-il une profonde faille fondamentale dans mon design? C'est mon premier gros projet WPF, et je suis en train de faire sur mon propre temps comme une expérience d'apprentissage, donc je ne suis certainement pas opposé à l'apprentissage d'une solution supérieure d'architecture.
OriginalL'auteur Greg D | 2009-03-05
Vous devez vous connecter pour publier un commentaire.
1: Oui, CommandTarget contrôles où la RoutedCommand commence routage.
2: ContextMenu a un PlacementTarget propriété qui permettra l'accès à votre UserControl:
Pour éviter de répéter ce dans tous les MenuItem vous pouvez utiliser un Style.
3 & 4: je dirais que votre désir est raisonnable. Depuis le gestionnaire Execute est sur la Fenêtre, il n'a pas d'importance pour l'instant, mais si vous aviez des différentes régions de la demande, chacun avec leur propre gestionnaire Execute pour la même commande, il importe d'où l'accent était mis.
OriginalL'auteur Robert Macnee
Similaire solution que j'ai trouvé était à l'aide de la propriété Tag de la mère de saisir le datacontext:
OriginalL'auteur David