如何在显示进度/取消对话框之前实现1s延迟?

时间:2012-09-20 11:34:19

标签: c# winforms multithreading async-await c#-5.0

我正在尝试构建一个进度/取消表单,以便在运行任何等待“操作”的WinForms应用程序中使用,同时为用户提供一些进度信息和取消操作的机会。

因为表单是使用ShowDialog()显示的,所以它是一种模式形式,可以很好地禁用下面的表单 - 所以我不需要乱用禁用其他表单上的所有控件。

我已经实现了它,我完全希望你撕成碎片:-),是等待Form.Load事件处理程序中的操作结果,然后在操作后关闭表单要么已完成(无论是因为它运行完成,被取消,还是引发异常)。

public partial class ProgressForm<T> : Form
{
    private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
    private Progress<string> _progress = new Progress<string>();
    private Func<IProgress<string>, CancellationToken, Task<T>> _operation = null;
    private Exception _exception = null;
    private T _result = default(T);


    public static T Execute(Func<IProgress<string>, CancellationToken, Task<T>> operation)
    {
        using (var progressForm = new ProgressForm<T>())
        {
            progressForm._operation = operation;

            progressForm.ShowDialog();

            if (progressForm._exception != null)
                throw progressForm._exception;
            else
                return progressForm._result;
        }
    }


    public ProgressForm()
    {
        InitializeComponent();

        this._progress.ProgressChanged += ((o, i) => this.ProgressLabel.Text = i.ToString());
    }

    private async void ProgressForm_Load(object sender, EventArgs e)
    {
        try
        {
            this._result = await this._operation(this._progress, this._cancellationTokenSource.Token);
        }
        catch (Exception ex) // Includes OperationCancelledException
        {
            this._exception = ex;
        }

        this.Close();
    }

    private void CancelXButton_Click(object sender, EventArgs e)
    {
        if (this._cancellationTokenSource != null)
            this._cancellationTokenSource.Cancel();
    }
}

这就是这样的:

int numberOfWidgets = ProgressForm<int>.Execute(CountWidgets);

...其中CountWidgets()是一个等待的东西(在这种情况下是一个返回Task<int>的函数,带有适当的IProgress和CancellationToken参数)。

到目前为止,它的效果非常好,但我想添加一个“功能”。理想情况下,我希望表单在(比如说)一秒钟内保持不可见状态,这样如果操作完全快速完成,则表单无法显示“闪烁”,然后立即再次隐藏。

所以,我的问题是如何在显示表单之前引入1s延迟。显然,我仍然想立即开始操作,但是当我“等待”操作的结果时,我不再控制(可以这么说),因为控制将返回给{{的调用者1}}事件处理程序 - 将继续显示表单的工作。

我怀疑基本上我真的需要第二个线程,并且我需要在阻塞主UI线程时在该线程上执行操作。 (我知道阻止UI线程是不受欢迎的,但在这种情况下,我认为它实际上是我需要的。)

创建线程的方法有很多种,我不知道如何在新的“async / await”世界中做到这一点......

1 个答案:

答案 0 :(得分:1)

如果您想延迟显示表单,我不建议您保留部分内容。我将独立调用该操作,然后创建一个Timer,其Tick事件处理程序检查任务是否完整,如果是,则不执行任何操作。否则,它应该创建表单,将IProgress<T>CancellationTokenSource以及任务传递给表单。您仍然可以等待已经启动的任务。对于要启动的任务,在创建表单之前需要进度对象和取消令牌 - 因此需要独立创建...