My Silverlight系列(9)—— 模拟Silverlight中的双击事件

也许是因为Silverlight是跑在浏览器上的缘故,也许是Silverlight才刚刚起步,从设计之初到现在,它对鼠标事件的响应,仍然只有可怜的MouseLeftButtonDown、MouseLeftButtonUp、MouseEnter、MouseLeave和MouseMove五个事件而已。且不论它并没有对右键和滚轮(这个也许是为了跨平台,据说MacOS是没有滚轮的)的支持,就连双击这个简单的事件它也没有包装。因此,我自己写了一个Helper,实现了在Silverlight中的双击事件。

我仔细的研究了WinForm中的双击事件,我发现WinForm中的事件还真是多,和点击有关的事件,就有MouseClick、MouseDown、MouseUp、MouseDoubleClick、Click、DoubleClick等等。。。其实可以毫不客气的说,所有的事件都是对MouseDown和MouseUp的封装,但是这样的确可以让开发人员感到非常的方便。经过研究我发现,如果用户双击某一个控件,第一次点击会触发Click事件,第二次点击会触发DoubleClick而Click不会触发,同时这两次点击,都会触发MouseDown事件。

那么,我在Silverlight上的模拟,至少要达到这个要求。但是考虑到Silverlight上鼠标事件较少,又没有对右键的支持,因此我决定将情况分成两种,一种是双击的第一次会触发单击事件,另一种是双击后,两次点击都不会触发单击事件。我想,后一种也是有一定需求的,比如我做了一个MediaPlayer,我双击是为了全屏观看,单击是为了控制播放、暂停,这时如果双击的时候也触发了单击事件,那么全屏之后就暂停了,那多不爽啊。

其实通过监视MouseLeftButtonDown事件,可以很简单的模拟双击事件,只需要不停记录点击的时间,并且和上一次点击的时间比较,如果时间差小于某一个值,则触发双击事件,某则触发发单击事件。这样做,能够实现WinForm那种单双击的机制,但是无法实现我说的第二种机制,即双击的时候,单击永远不会触发。为了实现这个功能,我加入了一个Timer,当确定无法实现双击的时候,我会通过它来触发单击,这样做会造成单击事件触发有一定的延迟,但是这一点延迟也是微不足道的,毕竟双击的两次点击间隔也不是很长。该类的核心实现代码如下:

 

ContractedBlock.gif ExpandedBlockStart.gif Code
  1    public class DoubleClickHelper
  2ExpandedBlockStart.gifContractedBlock.gif    {
  3ContractedSubBlock.gifExpandedSubBlockStart.gif        Constant#region Constant
  4        private const long m_DoubleClickInterval = 2000000;
  5        #endregion

  6
  7ContractedSubBlock.gifExpandedSubBlockStart.gif        Events#region Events
  8        public event EventHandler<MouseButtonEventArgs> DoubleClick;
  9        public event EventHandler<MouseButtonEventArgs> Click;
 10        #endregion
 Events
 11
 12ContractedSubBlock.gifExpandedSubBlockStart.gif        Field#region Field
 13        private DispatcherTimer m_Timer;
 14        private bool m_IsSpecial;
 15        private FrameworkElement m_Element;
 16        private long m_DoubleClickTicks = 0;
 17        private object Temp_Sender;
 18        private MouseButtonEventArgs Temp_EventArgs;
 19        #endregion

 20
 21ContractedSubBlock.gifExpandedSubBlockStart.gif        Property#region Property
 22        private FrameworkElement Element
 23ExpandedSubBlockStart.gifContractedSubBlock.gif        {
 24ExpandedSubBlockStart.gifContractedSubBlock.gif            get return m_Element; }
 25            set
 26ExpandedSubBlockStart.gifContractedSubBlock.gif            {
 27                if (value != null && m_Element != value)
 28ExpandedSubBlockStart.gifContractedSubBlock.gif                {
 29                    m_Element = value;
 30                    m_Element.MouseLeftButtonDown += new MouseButtonEventHandler(OnMouseLeftButtonDown);
 31                }

 32            }

 33        }

 34
 35        public bool IsSpecial
 36ExpandedSubBlockStart.gifContractedSubBlock.gif        {
 37ExpandedSubBlockStart.gifContractedSubBlock.gif            get return m_IsSpecial; }
 38            set
 39ExpandedSubBlockStart.gifContractedSubBlock.gif            {
 40                m_IsSpecial = value;
 41                if (IsSpecial)
 42ExpandedSubBlockStart.gifContractedSubBlock.gif                {
 43                    this.m_Timer = new DispatcherTimer();
 44                    this.m_Timer.Interval = TimeSpan.FromTicks(m_DoubleClickInterval);
 45                    this.m_Timer.Tick += new EventHandler(m_Timer_Tick);
 46                }

 47            }

 48        }

 49        #endregion

 50
 51ContractedSubBlock.gifExpandedSubBlockStart.gif        Construstor#region Construstor
 52        public DoubleClickHelper(FrameworkElement Element)
 53ExpandedSubBlockStart.gifContractedSubBlock.gif            : this(Element, false{ }
 54
 55
 56        public DoubleClickHelper(FrameworkElement Element, bool IsSpecial)
 57ExpandedSubBlockStart.gifContractedSubBlock.gif        {
 58            this.Element = Element;
 59            this.IsSpecial = IsSpecial;
 60        }

 61        #endregion
       
 62
 63ContractedSubBlock.gifExpandedSubBlockStart.gif        Event Handlers#region Event Handlers
 64        void m_Timer_Tick(object sender, EventArgs e)
 65ExpandedSubBlockStart.gifContractedSubBlock.gif        {
 66            RaiseSingleClick(Temp_Sender, Temp_EventArgs);
 67            m_Timer.Stop();
 68        }

 69
 70        void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
 71ExpandedSubBlockStart.gifContractedSubBlock.gif        {
 72            if (IsSpecial)
 73ExpandedSubBlockStart.gifContractedSubBlock.gif            {
 74                Temp_Sender = sender;
 75                Temp_EventArgs = e;
 76                m_Timer.Start();
 77            }

 78
 79            if (DateTime.Now.Ticks - m_DoubleClickTicks < m_DoubleClickInterval)
 80ExpandedSubBlockStart.gifContractedSubBlock.gif            {
 81                if (IsSpecial)
 82                    m_Timer.Stop();
 83                RaiseDoubleClick(sender, e);
 84            }

 85            else
 86ExpandedSubBlockStart.gifContractedSubBlock.gif            {
 87                if (!IsSpecial)
 88                    RaiseSingleClick(sender, e);
 89            }

 90            m_DoubleClickTicks = DateTime.Now.Ticks;
 91        }

 92        #endregion

 93
 94ContractedSubBlock.gifExpandedSubBlockStart.gif        Raise Events#region Raise Events
 95        void RaiseDoubleClick(object sender, MouseButtonEventArgs e)
 96ExpandedSubBlockStart.gifContractedSubBlock.gif        {
 97            if (DoubleClick != null)
 98                DoubleClick(sender, e);
 99        }

100
101        void RaiseSingleClick(object sender, MouseButtonEventArgs e)
102ExpandedSubBlockStart.gifContractedSubBlock.gif        {
103            if (Click != null)
104                Click(sender, e);
105        }

106        #endregion

107    }

 

对于这个类的用法,我认为很简单,只需要把你希望引发双击事件的UI元素(FrameworkElement)作为参数传递给这个类,并且为其规定双击是否在第一次点击触发单击即可(构造器已经重载,如果只传UI元素进去,那么默认与WinForm的机制是一样的)。但是值得一提的是,这个类是否能够使用,完全取决于它能否handle那个UI元素的MouseLeftButtonDown事件,由于一些特殊的原因,比如在某些类中,已经将MouseLeftButtonDown事件Handle过,并且将e.Handled设为true,那么我们将无法得知它何时触发MouseLeftButtonDown事件,还有如果事件路由被某些不可预测的原因阻击,那么我们也将无法得到MouseLeftButtonDown事件。因此,这个类也存在一定的局限性,不过还好,如果这个类不Work的话,那么你不用它而直接在代码里监视事件也不会Work,我做的也仅仅是对事件的进一步封装而已。

我做了一个测试,代码在这里:http://files.cnblogs.com/wodehuajianrui/DoubleClick.rar

转载于:https://www.cnblogs.com/wodehuajianrui/archive/2008/10/27/1320189.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值