How do I right click on a Context Menu button in WPF?
I am working on a WPF error logging application where when the user enters a new connection string, a connection button is created and displayed as a complex list in the sidebar.
I want to right click on these connection buttons to show the context menu of the button for View, Edit, Delete .
My MainWindow.xaml Sidebar Grid looks like this:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="318*" />
</Grid.ColumnDefinitions>
<ScrollViewer VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Disabled">
<StackPanel Name="listConnections" Grid.Column="0" Background="#4682b4" Margin="0,0,0,-0.2" >
</StackPanel>
</ScrollViewer>
</TabControl>
</Grid>
And I call Stackpanel listConnections
in my MainWindow.xaml.cs like this
public MainWindow()
{
InitializeComponent();
GetUserData();
//Button to create new connection
listConnections.Children.Add(new NewConnectionButton(this));
this.Closed += new EventHandler(MainWindow_Close);
}
WPF Right Click Event I tried to follow this link to create a right click event but it doesn't work for me. Can someone please help me on this please?
You have to put the context menu inside the button resources like
<NewConnectionButton.Resources>
<ContextMenu x:Key="connectionButtonContext" StaysOpen="true">
<MenuItem Header="Add" Click="InternalAddButton_Click"/>
<MenuItem Header="Delete" Click="InternalDeleteButton_Click"/>
<MenuItem Header="Edit" Click="InternalEditButton_Click"/>
</ContextMenu>
</NewConnectionButton.Resources>
This code should be inside NewConnectionButton
UserControl. The code in C # UserControl sign these events and publish them ( InternalAddButton_Click
, InternalDeleteButton_Click
, InternalEditButton_Click
), who uses a button. Then sign them into your MainWindow.
I would do the following here:
- create a context menu separately and assign it to each "connection" object in the user interface
- handle
MenuItem.Click
picks an event for each menu item - allow the selected item in the list and process it accordingly
MVVM and all of this is fine, of course, but this simple approach is at least a good place to start:
<Window x:Class="WpfApplication7.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<!-- Having CommandParameter is crucial here -->
<ContextMenu x:Key="contextMenu">
<MenuItem Header="View"
Click="View_OnClick"
CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Parent}"/>
<MenuItem Header="Edit"
Click="Edit_OnClick"
CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Parent}" />
<MenuItem Header="Delete"
Click="Delete_OnClick"
CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Parent}"/>
</ContextMenu>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="318*" />
</Grid.ColumnDefinitions>
<ScrollViewer VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Disabled">
<StackPanel Name="listConnections" Grid.Column="0" Background="#4682b4" Margin="0,0,0,-0.2" >
<Button Click="BtnAdd_OnClick">New Connection</Button>
</StackPanel>
</ScrollViewer>
</Grid>
</Window>
Code for:
using System;
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication7
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private static Label FindClickedItem(object sender)
{
var mi = sender as MenuItem;
if (mi == null)
{
return null;
}
var cm = mi.CommandParameter as ContextMenu;
if (cm == null)
{
return null;
}
return cm.PlacementTarget as Label;
}
private void BtnAdd_OnClick(object sender, RoutedEventArgs e)
{
listConnections.Children.Add(new Label
{
Content = "New Connection",
ContextMenu = (ContextMenu)Resources["contextMenu"]
});
}
private void View_OnClick(object sender, RoutedEventArgs e)
{
var clickedItem = FindClickedItem(sender);
if (clickedItem != null)
{
MessageBox.Show(" Viewing: " + clickedItem.Content);
}
}
private void Edit_OnClick(object sender, RoutedEventArgs e)
{
var clickedItem = FindClickedItem(sender);
if (clickedItem != null)
{
string newName = "Connection edited on " + DateTime.Now.ToLongTimeString();
string oldName = Convert.ToString(clickedItem.Content);
clickedItem.Content = newName;
MessageBox.Show(string.Format("Changed name from '{0}' to '{1}'", oldName, newName));
}
}
private void Delete_OnClick(object sender, RoutedEventArgs e)
{
var clickedItem = FindClickedItem(sender);
if (clickedItem != null)
{
string oldName = Convert.ToString(clickedItem.Content);
listConnections.Children.Remove(clickedItem);
MessageBox.Show(string.Format("Removed '{0}'", oldName));
}
}
}
}
This is how it looks:
Hope it helps