原連接: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