原连接:UWP忽略短期内重复触发的事件 - 超威蓝火html
作移动端开发的可能都会遇到这种需求,当用户点击一个按钮以后,因为没有异步,或者设备性能不好等等缘由,程序卡住了。可是用户不知道是咋回事啊,就开始狂点按钮,结果请求不少次资源,或者构造了不少重复视图。安卓上有不少介绍如何忽略重复点击的状况,uwp里我好像还没找到,那接下来就说一说个人方法吧。
首先是官方最经常使用的,从Windows诞生之初用到如今的,点击按钮以后把他Disable掉,等完成了在Enable。其实这算是最好的选择了,可是总归是麻烦了一些,尤为是在MVVM的时候,每一个Button都要单独绑定一个IsEnabled,因此接下来就仿照安卓上的通用处理方法试一下。
首先建立一个类,咱们就叫他EventWaiter吧,里面维护一个LastTime,一个IsEnabled,事件能够判断这个IsEnabled来知道,上一次点击和这一次点击的间隔是否是太短,从而决定是否要执行。git
public class EventWaiter { private DateTime _lastTime; public EventWaiter(double seconds) { Interval = TimeSpan.FromSeconds(seconds); } public EventWaiter(TimeSpan interval) { Interval = interval; } public EventWaiter() { Interval = TimeSpan.FromSeconds(0.1d); } //间隔 public TimeSpan Interval { get; set; } public bool IsEnabled { get { if(DateTime.Now - _lastTime > Interval) { _lastTime = DateTime.Now; return true; } return false; } } public void Reset() { _lastTime = DateTime.Now; } }
大概用法是这样的:github
var waiter = new EventWaiter(); var button = new Button(); button.Click += OnClick; private void OnClick(object sender,RoutedEventArgs e) { if(waiter.IsEnabled) { //do something } }
接下来就是第三种需求了。对于安卓iOS来讲,不多有SizeChanged,可是UWP不同啊,UWP能窗口运行啊,因此在一些要响应SizeChanged,在窗口大小改变的时候作一些很重操做的时候,拖拽窗口就会变得很是卡,因此我如今想忽略拖动窗口的中间过程,只让他响应最后状态。而上面的EventWaiter,是一段时间内只响应第一次事件的触发,和咱们的需求是彻底反着的。
这时候就要请救星:DispatcherTimer出来了(感谢小竹)。
大体思路呢,按时间顺序叙述,是当原事件触发时,让Timer开始运行;第二次触发事件时判断Timer是否运行,若是正在运行呢,就停掉从新启动,至关于重置了计时器;等Timer第一次跑完,执行Tick的时候停掉Timer,而且激活内部的事件去作真正的操做。
咱们再弄个新的类,起个名字叫EventDelayer(原谅我起名困难),里面须要维护一个DispatcherTimer,还要一个事件Arrived负责在最后被触发,和一个Delay()方法,负责进入触发判断。异步
public class EventDelayer { private DispatcherTimer _timer; public EventDelayer(double seconds) : this(TimeSpan.FromSeconds(seconds)) { } public EventDelayer(TimeSpan interval) { _timer = new DispatcherTimer(); _timer.Tick += _timer_Tick; Interval = interval; } public EventDelayer() : this(0.1) { } public TimeSpan Interval { get => _timer.Interval; set => _timer.Interval = value; } public bool ResetWhenDelayed { get; set; } public void Delay() { if (!_timer.IsEnabled) { _timer.Start(); } else { if (ResetWhenDelayed) { _timer.Stop(); _timer.Start(); } } } private void _timer_Tick(object sender, object e) { if (_timer.IsEnabled) { _timer.Stop(); } OnArrived(); } public event EventHandler Arrived; protected void OnArrived() { Arrived?.Invoke(this, EventArgs.Empty); } }
用法大概是这个样子:性能
var delayer = new EventDelayer(); delayer.Arrived += OnArrived; this.SizeChanged += OnSizeChanged; private void OnSizeChanged(object sender, SizeChangedEventArgs e) { delayer.Delay(); } private void OnArrived(object sender,EventArgs args) { //do something }
炒鸡完美。github:https://github.com/cnbluefire/ReaderView/tree/master/ReaderView/Common/Helpersthis