Silverlight开发中的疑难杂症-如何为Silverlight添加双击事件

在日常的开发中鼠标的事件是我们使用的最多的事件,但是在Silverlight中,只支持以下六种有限的鼠标事件:MouseEnterMouseLeaveMouseLeftButtonDownMouseLeftButtonUpMouseMoveMouseWheel。这给我们的开发造成了不小的麻烦,还好Silverlight支持强大的附加属性机制,这里就指导大家如何通过附加属性来给Silverlight添加鼠标的双击事件。

附加属性是Silverlight也是WPF中最具创新也是最强大的特性之一,它能够让你在不拥有控件的源码的情况下对其功能进行扩展。关于附加属性的强大我就不在这里叙述了,有感兴趣的朋友可以去查看WPF控件开发揭秘一书,里面有一张专门争对附加属性进行了介绍,网络上和园子里也早就有许多关于附加属性的文章。

这里直接进入主题,首先,我们需要对外提供两种双击事件的处理机制,一种是常用的事件机制,使用自带的MouseButtonEventHandler;另一种是现在比较流行的Command机制,使用ICommand接口。两个附加属性的定义如下:

附加属性的定义
#region MouseDoubleClick

public static MouseButtonEventHandler GetMouseDoubleClick(DependencyObject obj)
{
    
return (MouseButtonEventHandler)obj.GetValue(MouseDoubleClickProperty);
}

public static void SetMouseDoubleClick(DependencyObject obj, MouseButtonEventHandler value)
{
    obj.SetValue(MouseDoubleClickProperty, value);
}

public static readonly DependencyProperty MouseDoubleClickProperty = DependencyProperty.RegisterAttached(
    
"MouseDoubleClick",
    
typeof(MouseButtonEventHandler),
    
typeof(MouseEventHelper),
    
new PropertyMetadata(new PropertyChangedCallback(OnMouseDoubleClickChanged))); 

#endregion

#region MouseDoubleClickCommand

public static ICommand GetMouseDoubleClickCommand(DependencyObject obj)
{
    
return (ICommand)obj.GetValue(MouseDoubleClickCommandProperty);
}

public static void SetMouseDoubleClickCommand(DependencyObject obj, ICommand value)
{
    obj.SetValue(MouseDoubleClickCommandProperty, value);
}

public static readonly DependencyProperty MouseDoubleClickCommandProperty =
    DependencyProperty.RegisterAttached(
"MouseDoubleClickCommand"typeof(ICommand), typeof(MouseEventHelper), new PropertyMetadata(OnMouseDoubleClickChanged)); 

#endregion

附加属性在定义上与依赖属性的主要区别就是附加属性是通过DependencyProperty.RegisterAttached的方式进行注册的,而依赖属性是通过DependencyProperty.Register方法进行注册的。这里还提供了GetSet方法,这两个方法是提供给在Xaml代码中进行附加属性注册时使用的。大家在进行附加属性的定义时,可以通过输入propa再按一下Tab键进行代码生成。大家可以注意到,在两个属性的定义中我们都传入了一个PropertyChangedCallback,这就是所谓的扩展点,在这个回调中,我们可以根据自己的逻辑进行相应的处理,这里我们只是注册了UIElementMouseLeftButtonDown事件,这样可以让我们的附加属性能够作用于所有继承自UIElement的控件(基本上就是全部的控件了吧~)。

双击事件的实现思路非常简单,就是通过在MouseLeftButtonDown中记录鼠标点击的时间,然后用上次的点击时间跟这次的点击时间进行比较,如果两次点击间隔小于200ms则作为一次双击处理,触发对应的事件和命令,完整的代码如下:

 

MouseEventHelper
/// <summary>
/// Silverlight鼠标事件帮助类
/// </summary>
public class MouseEventHelper
{
    
#region Dependency Properties

    
#region 模拟鼠标双击事件

    
#region MouseDoubleClick

    
public static MouseButtonEventHandler GetMouseDoubleClick(DependencyObject obj)
    {
        
return (MouseButtonEventHandler)obj.GetValue(MouseDoubleClickProperty);
    }

    
public static void SetMouseDoubleClick(DependencyObject obj, MouseButtonEventHandler value)
    {
        obj.SetValue(MouseDoubleClickProperty, value);
    }

    
public static readonly DependencyProperty MouseDoubleClickProperty = DependencyProperty.RegisterAttached(
        
"MouseDoubleClick",
        
typeof(MouseButtonEventHandler),
        
typeof(MouseEventHelper),
        
new PropertyMetadata(new PropertyChangedCallback(OnMouseDoubleClickChanged))); 

    
#endregion

    
#region MouseDoubleClickCommand

    
public static ICommand GetMouseDoubleClickCommand(DependencyObject obj)
    {
        
return (ICommand)obj.GetValue(MouseDoubleClickCommandProperty);
    }

    
public static void SetMouseDoubleClickCommand(DependencyObject obj, ICommand value)
    {
        obj.SetValue(MouseDoubleClickCommandProperty, value);
    }

    
public static readonly DependencyProperty MouseDoubleClickCommandProperty =
        DependencyProperty.RegisterAttached(
"MouseDoubleClickCommand"typeof(ICommand), typeof(MouseEventHelper), new PropertyMetadata(OnMouseDoubleClickChanged)); 

    
#endregion

    
private static DateTime? _lastClickTime = null;
    
private const int MaxClickInterval = 200;//ms

    
private static void OnMouseDoubleClickChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        UIElement element 
= obj as UIElement;
        
if (element != null)
        {
            element.MouseLeftButtonDown 
+= new MouseButtonEventHandler(element_MouseLeftButtonDown);
        }
    }

    
/// <summary>
    
/// 通过检测两次鼠标单机的间隔来模拟鼠标双击事件
    
/// </summary>
    
/// <param name="sender"></param>
    
/// <param name="e"></param>
    static void element_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        
//进入双击事件
        if (_lastClickTime.HasValue && DateTime.Now.Subtract(_lastClickTime.Value).TotalMilliseconds <= MaxClickInterval)
        {
            
//触发事件
            MouseButtonEventHandler handler = (sender as UIElement).GetValue(MouseDoubleClickProperty) as MouseButtonEventHandler;
            
if (handler != null)
            {
                handler(sender, e);
            }
            ICommand command 
= (sender as UIElement).GetValue(MouseDoubleClickCommandProperty) as ICommand;
            
if (command != null)
            {
                
if (command.CanExecute(sender))
                {
                    command.Execute(sender);
                }
            }
            
//重新计时
            _lastClickTime = null;
        }
        
else
        {
            _lastClickTime 
= DateTime.Now;
        }
    } 

    
#endregion

    
#endregion
}

是不是觉得很简单?按照上面的流程大家就可以尽情的扩展Silverlight,帮她加上各种各样的功能了!~

posted on 2010-03-12 20:14 yingql 阅读(1833) 评论(21) 编辑 收藏

评论

#1楼 2010-03-13 01:29 silverlightchina      

尊敬的作者您好:

您的
"Silverlight开发中的疑难杂症-如何为Silverlight添加双击事件"文章已经被银光中国网(SilverlightChina.Net)转载收录,我们在文章明显位置标识您的原创版权信息,如果您对转载有异议,请您联系admin@silverlightchina.net,我们会及时回复。

感谢您提供优秀的Silverlight系列文章。

您的文章地址:http://silverlightchina.net/html/tips/2010/0312/831.html


银光中文网


 回复 引用 查看   

#2楼 2010-03-13 10:48 秀郎      

在xaml中如何去用MouseEventHelper呢?  回复 引用 查看   

#3楼[楼主] 2010-03-13 12:33 yingql      

@秀郎
先跟平常一样在上面添加对应名字控件的别名如:
xmlns:Helper="clr-namespace:YQL.Core.Extensions;assembly=YQL.Core.Silverlight"
然后用与下面类似的方法进行访问
<Grid Helper:MouseEventHelper.MouseDoubleClick="My_MouseDoubleClickEvent" Helper:MouseEventHelper.MouseDoubleClickCommand="{Binding Path=MouseDoubleClickCommand}">
 回复 引用 查看   

#4楼 2010-03-13 15:00 dino623      

实在是太GOOD GOB了,谢谢分享  回复 引用 查看   

#5楼[楼主] 2010-03-13 15:06 yingql      

@dino623
谢谢支持,不过GOB是啥意思哦?
 回复 引用 查看   

#6楼 2010-03-13 15:11 dino623      

@yingql
写错了,是Good Job才对(明明平时都是简写GJ的,偏偏就错了个“J”)。
最重要的是,终于知道ICommand怎么使用了,顺便摆脱
MouseClickManger mcm =new MouseClickManger(DataGrid);
mcm.DoubleClick+=.....
这种在代码中注册事件的写法
 回复 引用 查看   

#7楼[楼主] 2010-03-13 16:03 yingql      

@dino623
O(∩_∩)O~
 回复 引用 查看   

#8楼 2010-03-13 19:17 BenBen789      

未在类型“MouseEventHelper”中找到可附加的属性“MouseDoubleClick”  回复 引用 查看   

#9楼[楼主] 2010-03-13 19:21 yingql      

@BenBen789
?咋啦
 回复 引用 查看   

#10楼 2010-03-14 01:31 BenBen789      

@yingql
按照你的示例去试着运用,结果在 xaml 里提示:
未在类型“MouseEventHelper”中找到可附加的属性“MouseDoubleClick”
 回复 引用 查看   

#11楼[楼主] 2010-03-14 13:08 yingql      

@BenBen789
你可以在代码中通过MouseEventHelper.SetMouseDoubleClick(this, new MouseButtonEventHandler(MouseDoubleClick));的方式使用试试,我也不知道为什么在xaml中不行,不好意思哦
 回复 引用 查看   

#12楼 2010-03-15 09:22 BenBen789      

不知道楼主试的效果怎么样?
更多的时候不能正常触发。
 回复 引用 查看   

#13楼 2010-03-15 09:39 allentranks      

sl 4.0应该会对这方面支持更好:)  回复 引用 查看   

#14楼 2010-03-15 13:10 dino623      

改成MouseButtonUp好点,起码在 DataGrid中双击事件是要在MouseButtonUp上才起作用的  回复 引用 查看   

#15楼[楼主] 2010-03-15 19:08 yingql      

@BenBen789
我每次都成功哦,如果你不行的话可以把间隔设长点;
 回复 引用 查看   

#16楼[楼主] 2010-03-15 19:09 yingql      

@allentranks
还没用过SL4,不知道如何~
 回复 引用 查看   

#17楼[楼主] 2010-03-15 19:09 yingql      

@dino623
多谢提醒~
 回复 引用 查看   

#18楼 2010-04-23 15:45 DaveLin      

发现楼主的一个问题,你使用了Milliseconds属性来判断两次点击的时间间隔,会出现如下问题:
第一次点击出现在10.001秒,第二次出现在12.002秒,那么两个时间相减的Milliseconds属性值为1,出现错误.
建议你使用TotalMilliseconds熟悉,谢谢!
 回复 引用 查看   

#19楼[楼主] 2010-04-23 21:15 yingql      

@DaveLin
oh my god. 怎么会有这样的问题,是俺疏忽了,多谢提醒~
 回复 引用 查看   

#20楼 2010-11-02 17:20 TonyHoo      

<Grid Helper:MouseEventHelper.MouseDoubleClick="My_MouseDoubleClickEvent" Helper:MouseEventHelper.MouseDoubleClickCommand="{Binding Path=MouseDoubleClickCommand}">

请问楼主My_MouseDoubleClickEvent 方法在code中怎么定义?
 回复 引用 查看   

#21楼 2011-01-17 15:12 淳米粒      

请问楼主在代码里怎么写的?能否有一个完整的例子。为什么在XAMl中按照<Grid Helper:MouseEventHelper.MouseDoubleClick="My_MouseDoubleClickEvent" Helper:MouseEventHelper.MouseDoubleClickCommand="{Binding Path=MouseDoubleClickCommand}">这种格式总是会说文本My_MouseDoubleClickEvent没有实现MouseButtonHandler?  回复 引用 查看   

公告

昵称:yingql
园龄:3年10个月
粉丝:20
关注:2

导航

<2010年3月>
28123456
78910111213
14151617181920
21222324252627
28293031123
45678910

统计

  • 随笔 - 53
  • 文章 - 1
  • 评论 - 157
  • 引用 - 4

搜索

 

常用链接

我的标签

随笔分类

随笔档案

积分与排名

  • 积分 - 42275
  • 排名 - 2514

最新评论

阅读排行榜

评论排行榜

推荐排行榜