当前位置:首页 > Windows程序 > 正文

WPF 如何控制右键菜单ContextMenu的弹出

2021-05-26 Windows程序

在具体做一些项目的时候,有时候需要需要先左键点击某个节点,然后再右键点击节点的时候才弹出右键菜单,所以直接右键点击时需要禁用掉右键菜单,这里比如我们为Grid添加了ContextMenu,但是我们需要设置一个bool型的变量isSelected,当我们执行到MouseLeftButtonDown事件中的时候,我们就可以将isSelected设置为true,然后在Grid中添加PreviewMouseRightButtonUp="OnMouseRightButtonUp"(隧道事件路由)事件或者是MouseRightButtonUp(冒泡事件路由)事件,在本项目中两者都可以,但是不要添加在<Grid.ContextMenu/>及其子节点下面,这个稍后会介绍,然后在主程序中执行下面的代码:

private void OnMouseRightButtonUp(object  sender,MouseButtonEventArgs  e)

{

if(isSelected==true)

{

//使消息可以传递

e.Handled=false;

}

else

{

e.Handled=true;

}

isSelected=false;

}

这样当我们先左键点击某一个节点的时候,然后再点击右键的时候才能弹出ContextMenu,这里我们需要正确理解Handled的含义,Handled将路由事件标记为已处理的值。如果 Handled 的值为 true,则可以防止事件路由路径上的大多数处理程序再次处理同一事件。这在实际的事件处理中是非常有用的,因为WPF的这种层层嵌套的UI设计思想,使得某一个事件,例如UIElement.MouseLeftButtonDown在很多元素上都会触发,根据事件的不同类型,可以有冒泡触发或者是隧道的这种方式来触发,但事实上只有一个元素最终执行该事件,如果某一个元素已经执行过该事件,那么它就会将Handled 的值设为 true,这样事件就不会向下或者向上路由了,如果想让事件继续路由就要将Handled设置为false这个是非常重要的,下面的内容参考一下别人写的一篇博客,很有意义。

在读《WPF高级编程》,看到事件的上传和下传。有个例子:

前台代码:

<Window x:Class="TunnelingBubbling.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" > <Grid MouseLeftButtonDown="Grid_MouseLeftButtonDown" PreviewMouseLeftButtonDown="Grid_PreviewMouseLeftButtonDown"> <Button PreviewMouseLeftButtonDown="Button_PreviewMouseLeftButtonDown" MouseLeftButtonDown="Button_MouseLeftButtonDown"> <TextBox MouseLeftButtonDown="textBox1_MouseLeftButtonDown" PreviewMouseLeftButtonDown="textBox1_PreviewMouseLeftButtonDown"> </TextBox> </Button> </Grid> </Window>

分别为Grid,Button,TextBox定义了PreviewMouseLeftButtonDown和MouseLeftButtonDown事件,并且为Button定义的Click事件。

后台代码如下:

public partial class Window1 : Window { public Window1() { InitializeComponent(); } private void Grid_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { Debug.WriteLine("Grid_PreviewMouseLeftButtonDown"); } private void Button_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { Debug.WriteLine("Button_PreviewMouseLeftButtonDown"); } private void textBox1_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { Debug.WriteLine("textBox1_PreviewMouseLeftButtonDown"); } private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { Debug.WriteLine("Grid_MouseLeftButtonDown"); } private void Button_Click(object sender, RoutedEventArgs e) { Debug.WriteLine("Button_Click"); } private void textBox1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { Debug.WriteLine("textBox1_MouseLeftButtonDown"); } private void Button_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { Debug.WriteLine("Button_MouseLeftButtonDown"); } }

但是在执行的时候,MouseLeftButtonDown事件总是无法触发。查看了一些资料,才知道这是一个设计原则上的问题。控件在捕获了MouseLeftButtonDown事件后,会将该事件的“Handled”设置为True,这个属性是用在事件路由中的,当某个控件得到一个RoutedEvent,就会检测Handled是否为true,为true则忽略该事件。

并且,控件本身的Click事件,,相当于将MouseLeftButtonDown事件抑制(Supress)掉了,转换成了Click事件。所以,如果一定要使用这个事件的话,需要在初始化的函数里利用UIElement的AddHandler方法,显式的增加这个事件。

--------------------------------------------------------------------------------------------------

---------方法说明:---------------------------------------------------------------------------------

UIElement.AddHandler 方法 (RoutedEvent, Delegate, Boolean)

为指定的路由事件添加路由事件处理程序,并将该处理程序添加到当前元素的处理程序集合中。将 handledEventsToo 指定为 true 时,可为已标记为由其他元素在事件路由过程中处理的路由事件调用所提供的处理程序。

参数说明:

handledEventsToo类型:System..::.Boolean

温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/71587.html