J'ai une application WPF..Dans laquelle j'ai un contrôle Image dans un fichier Xaml.
Sur le clic droit de cette image, j'ai un menu contextuel.
Je voudrais avoir même pour être affiché sur "clic gauche" aussi.
Comment est-ce que je fais ceci de manière de MVVM?
Voici une solution uniquement XAML… .. Il suffit d'ajouter ce style à votre bouton… .. Cela entraînera l'ouverture du menu contextuel par un clic gauche ou droit. Prendre plaisir!
<Button Content="Open Context Menu">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<EventTrigger RoutedEvent="Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="ContextMenu.IsOpen">
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem />
<MenuItem />
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
Vous pouvez le faire en utilisant l'événement MouseDown d'une image comme ceci
<Image ... MouseDown="Image_MouseDown">
<Image.ContextMenu>
<ContextMenu>
<MenuItem .../>
<MenuItem .../>
</ContextMenu>
</Image.ContextMenu>
</Image>
Et ensuite, affichez le ContextMenu dans EventHandler dans le code derrière
private void Image_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
Image image = sender as Image;
ContextMenu contextMenu = image.ContextMenu;
contextMenu.PlacementTarget = image;
contextMenu.IsOpen = true;
}
}
Vous pouvez inventer votre propre DependencyProperty qui ouvre un menu contextuel lorsque vous cliquez sur l'image, comme ceci:
<Image Source="..." local:ClickOpensContextMenuBehavior.Enabled="True">
<Image.ContextMenu>...
</Image.ContextMenu>
</Image>
Et voici un code C # pour cette propriété:
public class ClickOpensContextMenuBehavior
{
private static readonly DependencyProperty ClickOpensContextMenuProperty =
DependencyProperty.RegisterAttached(
"Enabled", typeof(bool), typeof(ClickOpensContextMenuBehavior),
new PropertyMetadata(new PropertyChangedCallback(HandlePropertyChanged))
);
public static bool GetEnabled(DependencyObject obj)
{
return (bool)obj.GetValue(ClickOpensContextMenuProperty);
}
public static void SetEnabled(DependencyObject obj, bool value)
{
obj.SetValue(ClickOpensContextMenuProperty, value);
}
private static void HandlePropertyChanged(
DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
if (obj is Image) {
var image = obj as Image;
image.MouseLeftButtonDown -= ExecuteMouseDown;
image.MouseLeftButtonDown += ExecuteMouseDown;
}
if (obj is Hyperlink) {
var hyperlink = obj as Hyperlink;
hyperlink.Click -= ExecuteClick;
hyperlink.Click += ExecuteClick;
}
}
private static void ExecuteMouseDown(object sender, MouseEventArgs args)
{
DependencyObject obj = sender as DependencyObject;
bool enabled = (bool)obj.GetValue(ClickOpensContextMenuProperty);
if (enabled) {
if (sender is Image) {
var image = (Image)sender;
if (image.ContextMenu != null)
image.ContextMenu.IsOpen = true;
}
}
}
private static void ExecuteClick(object sender, RoutedEventArgs args)
{
DependencyObject obj = sender as DependencyObject;
bool enabled = (bool)obj.GetValue(ClickOpensContextMenuProperty);
if (enabled) {
if (sender is Hyperlink) {
var hyperlink = (Hyperlink)sender;
if(hyperlink.ContextMenu != null)
hyperlink.ContextMenu.IsOpen = true;
}
}
}
}
vous devez seulement ajouter le code dans la fonction Image_MouseDown
e.Handled = true;
Ensuite, il ne va pas disparaître.
vous pouvez lier la propriété Isopen du contextMenu à une propriété de votre viewModel telle que "IsContextMenuOpen" . mais le problème est que vous ne pouvez pas lier directement le contextmenu à votre viewModel car il ne fait pas partie de votre userControl hiarchy.So Pour résoudre ce problème, vous devez associer la propriété de balise au contexte dataontext de votre vue.
<Image Tag="{Binding DataContext, ElementName=YourUserControlName}">
<ContextMenu IsOpen="{Binding PlacementTarget.Tag.IsContextMenuOpen,Mode=OneWay}" >
.....
</ContextMenu>
<Image>
Bonne chance.
Si vous voulez faire cela uniquement dans Xaml sans utiliser de code-behind, vous pouvez utiliser le support des déclencheurs d'Expression Blend:
...
xmlns:i="schemas.Microsoft.com/expression/2010/interactivity"
...
<Button x:Name="addButton">
<Button.ContextMenu>
<ContextMenu ItemsSource="{Binding Items}" />
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:ChangePropertyAction TargetObject="{Binding ContextMenu, ElementName=addButton}" PropertyName="PlacementTarget" Value="{Binding ElementName=addButton, Mode=OneWay}"/>
<ei:ChangePropertyAction TargetObject="{Binding ContextMenu, ElementName=addButton}" PropertyName="IsOpen" Value="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button.ContextMenu>
</Button>
J'ai rencontré le même problème en cherchant une solution que je n'ai pas trouvée ici.
Je ne connais rien à MVVM, ce n'est donc probablement pas conforme à MVVM mais cela a fonctionné pour moi.
Étape 1: Donnez un nom à votre menu contextuel.
<Button.ContextMenu>
<ContextMenu Name="cmTabs"/>
</Button.ContextMenu>
Étape 2: Double-cliquez sur l'objet de contrôle et insérez ce code. L'ordre compte!
Private Sub Button_Click_1(sender As Object, e As Windows.RoutedEventArgs)
cmTabs.StaysOpen = True
cmTabs.IsOpen = True
End Sub
Étape 3: Profitez
Cela va réagir pour un clic gauche et droit. C'est un bouton avec ImageBrush avec un ControlTemplate.