关于WPF中的鼠标单击事件

总的来说,WPF对于UI方面的支持还是挺强大的,可以很方便地制作精美的UI,

可是习惯传统WinForm开发的程序员,一开始接触WPF可能会不太适应。

例如,传统WinForm中很多控件都有Text这个属性,大部分也都是继承于Control这个类,

而在WPF中,部分控件是有Text属性的,部分控件是有Content属性而没有Text属性的,

且有的控件是继承于Control,有的控件是继承于FrameworkElement,

第一次接触WPF的人可能会觉得有点乱,不太适应。

不过,不适应也只是暂时的,随着使用时间的增长,适应那也是迟早的事情了。

不过呢,大多数人会发现一个问题,就是在WPF中大部分控件都没有Click事件,也就是鼠标单击事件。

在开发过程中,有的时候我们需要自定义按钮样式,传统WinForm一般是放一个Image,然后加上Click事件来模拟按钮,

然而在WPF中我们并不能简单地这么做,因为WPF中的Image没有Click事件。

虽然WPF中的Button支持Click事件且能通过设置背景图片来自定义样式,可是Button同时还会有个Hover的效果,我们又不需要这个效果,会影响美观,

要去掉这个Hover效果只能通过Style的方式来修改,对于初级水平的人员来说,可能会有点难。

最终比较简单的方式,还是回归到Image控件+模拟的Click事件来实现这个效果。

很多人会使用MouseLeftButtonDown或MouseLeftButtonUp来模拟这个Click事件,但实际上都不完美,因为都有缺点。

传统的Click事件,是在鼠标放开的一瞬间出发的,也就是说按照Down->Click->Up的顺序触发事件,

触发Down事件的时候Click事件并没有触发,只有在触发Up事件的之前会同时触发Click事件。

当然,有的程序语言中,是按照Down->Up->Click的顺序触发事件的,反正至少在.NET中是按照Down->Click->Up的顺序触发事件。

按照这个顺序来看的话,直接用MouseLeftButtonDown代替Click肯定是不妥的;

如果用MouseLeftButtonUp来代替Click呢,一般情况下问题也不大,但如果我在别的地方点击再移动到Image上再Up呢,这个时候就有问题了

我参考这个顺序做了一个模拟Click事件的函数,代码如下:

/// <summary>
/// 为目标控件附加一个模拟的鼠标单击事件
/// </summary>
/// <param name="control">需要附加事件的控件</param>
/// <param name="handler">鼠标单击事件的处理函数</param>
/// <remarks>
/// By 风の雪
/// http://www.canaansky.com/
/// 在目标控件上MouseDown->MouseLeave->MouseEnter->MouseUp同样有效
/// </remarks>
bool EmulateClickEvent(FrameworkElement control, MouseButtonEventHandler handler)
{
    if (control == null || handler == null) return false;
    int status = 0;
    control.MouseEnter += delegate { if (status == 0) status = -1; };
    control.MouseLeave += delegate { status[0] = 0; };
    control.MouseLeftButtonDown += delegate { status = 1; };
    control.MouseLeftButtonUp += delegate(object sender, MouseButtonEventArgs e) { if (status > 0) handler(sender, e); status = 0; };
    return true;
}

调用方法嘛,很简单的,调用该函数,同时传递目标控件和事件处理函数即可,如:

Image image = new Image();
EmulateClickEvent(image, ImageOnClick);

void ImageOnClick(object sender, MouseButtonEventArgs e)
{
    MessageBox.Show("Hello World!");
}
此条目发表在技术随笔分类目录。将固定链接加入收藏夹。

关于WPF中的鼠标单击事件》有 1 条评论

  1. billypon说:

    注意一下,就是这个函数没有处理双击时情景,所以默认情况下出发双击事件的时候会同时触发两次单击,请自行处理这种情况。

发表评论