我正在尝试构建一个进度/取消表单,以便在运行任何等待“操作”的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”世界中做到这一点......
答案 0 :(得分:1)
如果您想延迟显示表单,我不建议您保留部分内容。我将独立调用该操作,然后创建一个Timer
,其Tick
事件处理程序检查任务是否完整,如果是,则不执行任何操作。否则,它应该创建表单,将IProgress<T>
和CancellationTokenSource
以及任务传递给表单。您仍然可以等待已经启动的任务。对于要启动的任务,在创建表单之前需要进度对象和取消令牌 - 因此需要独立创建...