我目前正在一个Windows.Forms项目中工作,在这个项目中,我需要在任务运行时显示一个响应性的反馈表单,这是非常常见的。这些任务通常需要5到10秒左右才能完成,在任务成功完成或失败之前,用户无法做任何其他事情。
为了保持UI响应性,我编写了一个小助手类。我对任务和异步编程环境非常陌生,所以我不确定我是在这里过火还是走错了方向:
这是一个小助手类:
internal sealed class TaskManagerWithFeedbackDialog<TController> where TController : IViewController, new()
{
public static Task<TReturn> RunTask<TReturn>(Func<TReturn> func)
{
if (func == null)
{
throw new ArgumentNullException("func");
}
var manager = new _AsyncTaskManager<TReturn>(func);
using (var view = new TController())
{
var task = manager.Start(view);
view.ShowViewDialog();
return task;
}
}
private class _AsyncTaskManager<T>
{
private readonly Func<T> taskFunc;
public _AsyncTaskManager(Func<T> func)
{
taskFunc = func;
}
public Task<T> Start(IViewController feedBackView)
{
var task = Task.Factory.StartNew(taskFunc);
task.ContinueWith(t =>
{
feedBackView.CloseView();
}, TaskContinuationOptions.OnlyOnFaulted);
task.ContinueWith(t =>
{
feedBackView.CloseView();
return t.Result;
}, TaskContinuationOptions.NotOnFaulted);
return task;
}
}
}IViewController.CloseView()的实现如下所示:
public virtual void CloseView()
{
if (View.InvokeRequired)
{
View.Invoke(new Action(View.Close));
}
else
{
View.Close();
}
}另一个我不确定的问题是,处理ArregateException的最佳地点在哪里?现在我不处理任何事情,因为如果任务失败,我不需要清理任何东西。我只需检查返回的任务是否有任何错误。这样做对吗?异步任务总是“默默地”失败吗?如果我需要清理,它会在哪里?在.ContinueWith( .... , TaskContinuationOptions.OnlyOnFaulted)里面?
发布于 2016-01-31 03:21:04
这里更新的是一些清理。现在,您可以在阻塞开始之前返回对Task<T>的引用:TaskWithFeedback.Run()是一个非阻塞调用。它还与视图中的Form.Show()和Form.ShowModel()一起工作。
class TaskWithFeedback<TViewController>
where TViewController : IViewController, new()
{
public static async Task<T> Run<T>(Func<T> function)
{
var context = TaskScheduler.FromCurrentSynchronizationContext();
var view = new TViewController();
var opening = new Task(view.ShowViewDialog);
opening.Start(context);
var task = Task.Run(function);
var closing = task
.ContinueWith(t => view.CloseViewDialog(), context);
try
{
return await task;
}
finally
{
await opening;
await closing;
}
}
}示例:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private async void button1_Click(object sender, EventArgs e)
{
Text = await TaskWithFeedback<Form2>.Run(() =>
{
Thread.Sleep(3000);
return "Hello!";
});
}
}
class Form2 : Form, IViewController
{
public void ShowViewDialog() => ShowDialog();
public void CloseViewDialog() => Close();
}https://codereview.stackexchange.com/questions/118248
复制相似问题