.NET 多執行緒開發總結(四)——藉助非同步語法實現可延時觸發的按鈕
阿新 • • 發佈:2021-01-07
轉眼又是一年,作為開年的第一篇部落格,先寫點簡單的熱熱手,畢竟也好久沒寫了。
如題,這是一篇實戰型別的文章,之所以放到“多執行緒開發”這個系列來呢,是因為…Emmmm,沒有理由,就是想放這(任性**_**)。
進入正題>>>
在日常開發中,會遇到如下一些情況:
①按鈕點選後隔一段時間方可再次點選,如:傳送驗證碼
②按鈕載入後隔一段時間方可點選,如:閱讀條款後已同意按鈕
③按鈕點選後隔一段時間才會觸發事件,如:點選查詢按鈕後指定時間無響應則主動結束
針對①②兩種情況,我們可以聯合起來分析,如在Click事件或Load事件觸發後禁用按鈕一段時間即可。這段程式碼非常簡單,非常符合此篇部落格的主題。
public async void DelayToEnable(int milliseconds)
{
this.IsEnabled = false;
await Task.Delay(milliseconds);
this.IsEnabled = true;
}
針對第③種情況,原本也可以用以上方法進行稍作調整來實現,但為了體現封裝性,也方便日後使用,所以還是繼承Button重寫了一些東西。
public class DelayButton : System.Windows.Controls.Button
{
/// <summary>
/// 延時啟用
/// </summary>
/// <param name="milliseconds"></param>
public async void DelayToEnable(int milliseconds)
{
this.IsEnabled = false;
await Task.Delay(milliseconds);
this.IsEnabled = true;
}
/// <summary>
/// 取消延時觸發的令牌
/// </summary>
private CancellationTokenSource m_DelayTriggerCts;
/// <summary>
/// 延時觸發間隔,單位(ms)
/// </summary>
public int DelayTriggerInterval
{
get { return (int)GetValue(DelayTriggerIntervalProperty); }
set { SetValue(DelayTriggerIntervalProperty, value); }
}
// Using a DependencyProperty as the backing store for DelayTriggerInterval. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DelayTriggerIntervalProperty =
DependencyProperty.Register(nameof(DelayTriggerInterval), typeof(int), typeof(DelayButton), new PropertyMetadata(0));
/// <summary>
/// 延時觸發路由事件
/// </summary>
public static readonly RoutedEvent DelayTriggerRoutedEvent =
EventManager.RegisterRoutedEvent("DelayTrigger", RoutingStrategy.Bubble, typeof(EventHandler<RoutedEventArgs>), typeof(DelayButton));
public event RoutedEventHandler DelayTrigger
{
add { this.AddHandler(DelayTriggerRoutedEvent, value); }
remove { this.RemoveHandler(DelayTriggerRoutedEvent, value); }
}
/// <summary>
/// 取消延時觸發
/// </summary>
public void CancelDelayTrigger()
{
m_DelayTriggerCts?.Cancel();
}
protected override async void OnClick()
{
base.OnClick();
try
{
m_DelayTriggerCts = new CancellationTokenSource();
await Task.Delay(DelayTriggerInterval, m_DelayTriggerCts.Token);
RoutedEventArgs args = new RoutedEventArgs(DelayTriggerRoutedEvent, this);
this.RaiseEvent(args);
}
catch (Exception)
{
Console.WriteLine("The delay trigger has been cancelled.");
}
finally
{
m_DelayTriggerCts.Dispose();
m_DelayTriggerCts = null;
}
}
}
(增加一個可以手動取消延遲的令牌,可以在長時間的延遲等待過程中隨時結束)