在具体做一些项目的时候,有时候需要需要先左键点击某个节点,然后再右键点击节点的时候才弹出右键菜单,所以直接右键点击时需要禁用掉右键菜单,这里比如我们为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"
Width="313" Height="271" Name="mygrid">
<Button PreviewMouseLeftButtonDown="Button_PreviewMouseLeftButtonDown"
MouseLeftButtonDown="Button_MouseLeftButtonDown" Click="Button_Click" Name="btnGo">
<TextBox Name="textBox1" Width="173" Height="27"
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

如果为 true,则将按以下方式注册处理程序:即使路由事件在其事件数据中标记为已处理,也会调用该处理程序;如果为 false,则使用默认条件注册处理程序,即当路由事件被标记为已处理时,将不调用处理程序。

默认值为 false。

修改后的程序代码如下:

 public Window1()
{
InitializeComponent();
mygrid.AddHandler(Grid.MouseLeftButtonDownEvent, new MouseButtonEventHandler(this.Grid_MouseLeftButtonDown), true);
btnGo.AddHandler(Button.MouseLeftButtonDownEvent, new MouseButtonEventHandler(this.Button_MouseLeftButtonDown), true);
textBox1.AddHandler(TextBox.MouseLeftButtonDownEvent, new MouseButtonEventHandler(this.textBox1_MouseLeftButtonDown), true);
}   

  再次运行,调用成功,事件的执行顺序是:

次序

控件

事件

事件类型

1

Grid PreviewMouseLeftButtonDown

下传

2

Button PreviewMouseLeftButtonDown

下传

3

TextBox PreviewMouseLeftButtonDown

下传

4

TextBox MouseLeftButtonDown

上传

5

Button MouseLeftButtonDown

上传

6

Grid MouseLeftButtonDown

上传

  如果点击Button,则事件的执行顺序是:

次序

控件

事件

事件类型

1

Grid PreviewMouseLeftButtonDown

下传

2

Button PreviewMouseLeftButtonDown

下传

3

Button MouseLeftButtonDown

上传

4

Grid MouseLeftButtonDown

上传

5

Button Click

  最后补充一点:

  在事件处理程序中,可以取消事件处理,查找事件的源元素

  例如在下面的代码中:

private void Button_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Debug.WriteLine("Button_PreviewMouseLeftButtonDown");
// e.Handled = true;
// Button myButton = e.Source as Button;
}  

  1.取消事件处理:  设置 e.Handled = true;

  2.在事件处理程序中查找源元素:  e.Source 传递一个实际对象实例,可以将其强制转换为System.Windows.Controls.Button类型,通过这个变量,可以访问这个控件提供的所有本地属性,方法和事件。

WPF 如何控制右键菜单ContextMenu的弹出的更多相关文章

  1. 【WPF】右键菜单ContextMenu可点击区域太小的问题

    问题描述 正常使用右键菜单ContextMenu时,如果菜单项是不变的,可以直接在XAML中写死,如下是给一个Button按钮添加了右键菜单功能. <Button Content="T ...

  2. wpf datagrid设置右键菜单打开时选中项的背景色

    原文:wpf datagrid设置右键菜单打开时选中项的背景色 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/huangli321456/artic ...

  3. jQuery右键菜单contextMenu实例

    URL: http://www.cnblogs.com/whitewolf/archive/2011/09/28/2194795.html http://www.blogjava.net/superc ...

  4. ExtJS配置TabPanel的鼠标右键菜单(ContextMenu)功能

    更新记录 2022年6月14日 发布. 2022年6月13日 初稿. TabPanel的鼠标右键菜单(ContextMenu)功能介绍 开源的TabPanel组件很少做到拖拽调整tab顺序功能的,支持 ...

  5. web标准(复习)--4 纵向导航菜单及二级弹出菜单

    今天我们开始学习纵向导航菜单及二级弹出菜单,包含以下内容和知识点: 纵向列表 标签的默认样式 css派生选择器 css选择器的分组 纵向二级列表 相对定位和绝对定位 一.纵向列表纵向列表或称为纵向导航 ...

  6. Web标准:四、纵向导航菜单及二级弹出菜单

    Web标准:四.纵向导航菜单及二级弹出菜单 知识点: 1.纵向列表 2.标签的默认样式 3.css派生选择器 4.css选择器的分组 5.纵向二级列表 6.相对定位和绝对定位   1)纵向列表 可以看 ...

  7. jQuery右键菜单contextMenu使用实例

    在最近项目中需要频繁的右键菜单操作.我采用了contextMenu这款jQuery插件. 参考网址:http://www.jb51.net/article/58709.htm 官网demo http: ...

  8. Jquery 右键菜单(ContextMenu)插件使用记录

    目前做的项目需要在页面里面用右键菜单,在网上找到两种jquery的右键菜单插件,但是都有各种问题.所以就自己动手把两种插件结合了下. 修改后的右键菜单插架可以根据绑定的触发页面元素不同,复用同一个菜单 ...

  9. 鼠标右键Table的td弹出多级菜单,双击td编辑

    <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="C ...

随机推荐

  1. promise-不使用catch出现warning的原因

    今天在使用node运行js文件时,返回了下面的错误和警告,警告部分主要是因为使用了promise,但是没有使用catch来捕捉错误.更详细的解释在下面,这是nodejs文档的process模块的一部分 ...

  2. Druid加密

    至于为什么加密,主要防止一些过多人知道数据库密码,可能造成公司的损失,同时也避免一些潜在的危害,因此,数据库密码最好还是只有几个人知道,太多人知道的话,影响不好. 最近删库的事情,太多了,个人觉得一个 ...

  3. [转]ubuntu下解压zip文件

    1.功能作用:解压缩zip文件 2.位置:/usr/bin/unzip 3.格式用法:unzip [-Z] [-opts[modifiers]] file[.zip] [list] [-x xlist ...

  4. 编写简单Linux内核模块

    模块代码如下 //main.c #include <linux/kernel.h> #include <linux/module.h> #include <linux/i ...

  5. 【Codeforces 17E】Palisection

    Codeforces 17 E 题意:给一个串,求其中回文子串交叉的对数. 思路1:用哈希解决.首先求出每个点左右最长的回文串(要分奇数长度和偶数长度),然后记录经过每个点的回文串的个数,以及它们是在 ...

  6. SkylineGlobe 如何实现二次开发加载KML文件

    示例代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www ...

  7. highcharts中数据列点击事件

    Highcharts.chart('container', { xAxis: { categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul ...

  8. Linux查看特定端口是否被占用并kill掉相关进程

    今天在搭建Zookeeper集群的时候,需要频繁启动zookeeper,但是启动的时候,有时会提示下列错误信息: zookeeper需要的地址已经被占用了,其实是因为上一次的zookeeper没有关闭 ...

  9. 设计模式:装饰模式(decorate)

    还是那几句话: 学无止境,精益求精 十年河东,十年河西,莫欺少年穷 学历代表你的过去,能力代表你的现在,学习代表你的将来 废话不多说,直接进入正题: 今天学习了装饰模式,但是代码看不太懂,于是我将装饰 ...

  10. 【UFUN开发板评测】小巧而不失精致,简单而不失内涵——uFun开发板开箱爆照

    关于uFun学习板--"满满的爱和正能量" uFun是由@张进东 张工组织发起的一个开源的学习板,设计初衷是为了帮助学生更好的理解电子知识和开发技巧,同时又能对学生毕业找工作有很明 ...