如何在 WPF 中制作右键单击按钮上下文菜单?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/43547647/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to make right click Button Context menu in WPF?
提问by StraightUp
I am working on a WPF error logging app, where when a user enters a new connection string, a connection button is created and shown as stacked list on the sidebar.
我正在开发一个 WPF 错误日志应用程序,当用户输入新的连接字符串时,会创建一个连接按钮并在侧边栏上显示为堆叠列表。
I want to make a right click event on those connection buttons to show a Button context menu for View, Edit, Delete.
我想在这些连接按钮上创建一个右键单击事件,以显示View、Edit、Delete的 Button 上下文菜单。
My MainWindow.xamlSidebar grid is like this,
我的MainWindow.xaml侧边栏网格是这样的,
<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 am calling the Stackpanel listConnectionsin my MainWindow.xaml.cslike this
Stackpanel listConnections我像这样在我的MainWindow.xaml.cs 中调用
public MainWindow()
{
InitializeComponent();
GetUserData();
//Button to create new connection
listConnections.Children.Add(new NewConnectionButton(this));
this.Closed += new EventHandler(MainWindow_Close);
}
Right-Click event WPF I tried to follow this link to create the right click event, but it is not working out for me. Can someone please assist me in this please?
右键单击事件 WPF我试图按照此链接创建右键单击事件,但它对我不起作用。有人可以帮助我吗?
回答by aperezfals
You should put a context menu inside the resources of the button, like this
您应该在按钮的资源中放置一个上下文菜单,如下所示
<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 the NewConnectionButtonUserControl. In the UserControlC# code, subscribe to those events and expose them
(InternalAddButton_Click, InternalDeleteButton_Click, InternalEditButton_Click) to who uses the Button. Then, subscribe to them in your MainWindow.
此代码应该在NewConnectionButtonUserControl 内。在UserControlC# 代码中,订阅这些事件并将它们 ( InternalAddButton_Click, InternalDeleteButton_Click, InternalEditButton_Click)公开给使用Button 的人。然后,在您的MainWindow.
回答by alex.b
What I'd do here would be the following:
我会在这里做的是以下内容:
- create context menu separately and assign it to every "connection" object on the UI
- handle
MenuItem.Clickclicks event for every menu item - resolve the clicked item in a list and process it respectively
- 单独创建上下文菜单并将其分配给 UI 上的每个“连接”对象
- 处理
MenuItem.Click每个菜单项的点击事件 - 解析列表中点击的项目并分别处理
MVVM and all that is certainly good but this straightforward approach is at least good place to start:
MVVM 和所有这些当然很好,但这种简单的方法至少是一个很好的起点:
<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-behind:
代码隐藏:
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 like:
这是它的样子:
Hope this helps
希望这可以帮助


