长时间操作时禁用按钮

本文关键字:按钮 操作 长时间 | 更新日期: 2023-09-27 18:11:23

在长时间操作期间,我想禁用按钮并清除文本块。

On button click事件在绘制屏幕之前被完全处理,因此按钮永远不会被明显禁用

private bool btnEnabled = true;
public bool BtnEnabled
{
    get { return btnEnabled; }
    set
    {
        if (value == btnEnabled)
            return;
        btnEnabled = value;
        NotifyPropertyChanged("BtnEnabled");
    }
}
private string results = "start";
public string Results
{
    get { return results; }
    set
    {
        if (value == results)
            return;
        results = value;
        NotifyPropertyChanged("Results");
    }
}
private void btn_Click(object sender, RoutedEventArgs e)
{
    BtnEnabled = false;
    Results = string.Empty;
    // whould like to displany wait spinner
    LongProcess();
    BtnEnabled = true;
}
private void LongProcess()
{
    //database query
    System.Threading.Thread.Sleep(10000);
    Results = "this is the results";
}

如何使按钮在长事件期间禁用?

我遇到的问题是用户感到沮丧,开始点击,这些点击都在队列中,并得到处理。

长时间操作时禁用按钮

要回答您的特定问题,您可以使用以下代码让UI处理消息(在将按钮设置为禁用之后):

Application.Current.Dispatcher.Invoke(
             DispatcherPriority.Background, 
             new Action(delegate { })
           );

或者更完整的:

public void DoEvents()
{
    DispatcherFrame frame = new DispatcherFrame();
    Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
        new DispatcherOperationCallback(ExitFrame), frame);
    Dispatcher.PushFrame(frame);
}
public object ExitFrame(object f)
{
    ((DispatcherFrame)f).Continue = false;
    return null;
}

然后,不建议使用(它相当于在Winforms上使用Application.DoEvents(),它有许多警告,应该像瘟疫一样避免,除非您知道自己在做什么)。长时间密集的操作不应该在UI线程上完成,或者如果它们不是CPU密集的,您可以使用async/await

这就是我最后的结果

private async void btn_Click(object sender, RoutedEventArgs e)
{
    BtnEnabled = false;
    Results = string.Empty;
    // whould like to displany wait spinner
    //LongProcess();
    cts = new CancellationTokenSource();
    try
    {
        //cts.Cancel(); just for test
        string result = await WaitAsynchronouslyAsync(cts.Token);
        //string result = await WaitSynchronously();
        BtnEnabled = true;
        Results = result;
    }
    catch (OperationCanceledException)
    {
        Results = "Operation canceled";  // this is not called
    }
    cts = null;
}
// The following method runs asynchronously. The UI thread is not
// blocked during the delay. You can move or resize the Form1 window 
// while Task.Delay is running.
public async Task<string> WaitAsynchronouslyAsync(CancellationToken ct)
{
    //DataBaseQuery();  // this just runs async
    //SqlCommand cmd = new SqlCommand();
    //await cmd.ExecuteScalarAsync(ct);
    await Task.Delay(10000);
    return "Finished";
}