我有遗留代码,可以在UI线程上执行一些非常长的操作。 我想要做的是显示带有消息的进度条并在另一个线程上运行该工作。不幸的是,目前我无法访问VS2012,因此我无法使用 async 关键字。 我已经编写了一些代码,它们可以正常运行0-1参数,并且使用 Action 没有返回值。 但是当我尝试调整它以支持Func时,我遇到了一些问题 调用任务并返回TResult。 附件是我的原始代码,将不胜感激任何建议。谢谢,Omer
public partial class FreeProgressBarFrm : System.Windows.Forms.Form
{
#region Members
/// <summary>
/// timer for the progress bar.
/// </summary>
private Timer m_Timer = new Timer();
/// <summary>
/// Delegate for the background operation to perform.
/// </summary>
private Action m_backgroundOperation;
/// <summary>
/// Standard operation to show the user while the operation is in progress.
/// </summary>
private static readonly string m_performingUpdatesMessage = IO_Global.GetResourceString("Performing updates, please wait", "Performing updates, please wait", null);
#endregion
#region Constructor
/// <summary>
/// Constructor
/// </summary>
/// <param name="backgroundDelegate"> Delegate for the background operation to perform</param>
/// <param name="operationName">meessage to show the user while the operation is in progress.</param>
public FreeProgressBarFrm(Action backgroundDelegate, string operationName)
{
InitializeComponent();
m_backgroundOperation = backgroundDelegate;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.lblOperation.Text = operationName;
m_Timer.Interval = 1000;
m_Timer.Tick += new EventHandler(m_Timer_Tick);
}
/// <summary>
/// Constructor , for progressbar with defalt user message (performing updates, please wait).
/// </summary>
/// <param name="backgroundDelegate"> Delegate for the background operation to perform</param>
/// <param name="operationName">operation display name</param>
public FreeProgressBarFrm(Action backgroundDelegate): this(backgroundDelegate, m_performingUpdatesMessage)
{
}
#endregion
#region Methods
/// <summary>
/// Call this method to begin backgorund operation while
/// showing the progress bar to the client.
/// </summary>
public void Wait()
{
ShowDialog(ControlsHelper.MainFrm);
}
/// <summary>
/// Advance the progress bar
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void m_Timer_Tick(object sender, EventArgs e)
{
PerformStep();
}
/// <summary>
/// Advance the progress bar
/// </summary>
private void PerformStep()
{
this.progressBar1.PerformStep();
this.lblOperation.Refresh();
if (this.progressBar1.Value == this.progressBar1.Maximum)
{
this.progressBar1.Value = this.progressBar1.Minimum;
}
}
/// <summary>
/// Load the form , start the progress bar and backroud task.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ProgressBarFrm_Load(object sender, EventArgs e)
{
m_Timer.Start();
this.lblOperation.Refresh();
Task task = new Task(m_backgroundOperation);
Task UITask = task.ContinueWith(delegate { OnWorkCompleted(); },
TaskScheduler.FromCurrentSynchronizationContext());
try
{
task.Start();
}
catch (Exception)
{
Close();
throw;
}
}
/// <summary>
/// Called when the work has been completed.
/// </summary>
private void OnWorkCompleted()
{
Close();
}
/// <summary>
/// Close the timer.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ProgressBarFrm_FormClosing(object sender, FormClosingEventArgs e)
{
if (m_Timer != null)
{
m_Timer.Dispose();
m_Timer = null;
}
}
#endregion
}
答案 0 :(得分:1)
这是我执行某些异步工作的方式,
public static class TaskExecuter
{
private static readonly ThreadLocal<List<BackgroundTask>> TasksToExecute =
new ThreadLocal<List<BackgroundTask>>(() => new List<BackgroundTask>());
public static Action<Exception> ExceptionHandler { get; set; }
public static void ExecuteLater(BackgroundTask task)
{
TasksToExecute.Value.Add(task);
}
public static void Discard()
{
TasksToExecute.Value.Clear();
}
public static void StartExecuting()
{
var value = TasksToExecute.Value;
var copy = value.ToArray();
value.Clear();
if (copy.Length > 0)
{
Task.Factory.StartNew(() =>
{
foreach (var backgroundTask in copy)
ExecuteTask(backgroundTask);
}, TaskCreationOptions.LongRunning)
.ContinueWith(task =>
{
if (ExceptionHandler != null)
ExceptionHandler(task.Exception);
}, TaskContinuationOptions.OnlyOnFaulted);
}
}
public static void ExecuteTask(BackgroundTask task)
{
task.Run();
}
}
这是基类
public abstract class BackgroundTask
{
protected readonly Logger Logger = LogManager.GetCurrentClassLogger();
protected virtual void Initialize()
{
}
protected virtual void OnError(Exception e)
{
//do some work
}
public bool? Run()
{
Logger.Info("Started task: {0}", GetType().Name);
Initialize();
try
{
Execute();
TaskExecuter.StartExecuting();
return true;
}
catch (Exception e)
{
Logger.ErrorException("Could not execute task " + GetType().Name, e);
OnError(e);
return false;
}
finally
{
TaskExecuter.Discard();
Logger.Info("Finished task: {0}", GetType().Name);
}
}
public abstract void Execute();
}
以下是使用
的示例public class SendEmailTask : BackgroundTask
{
private const string MailServerIp = "yourip";
public string[] To { get; set; }
public string From { get; set; }
public string Template { get; set; }
public object ViewContext { get; set; }
public string[] Attachments { get; set; }
public string Subject { get; set; }
public override void Execute()
{
MailMessage message = new MailMessage();
try
{
MailAddress mailAddress = new MailAddress(From);
message.From = mailAddress;
foreach (string to in To) message.To.Add(to);
message.Subject = Subject;
if (Attachments.ReturnSuccess())
{
foreach (string attachment in Attachments)
message.Attachments.Add(new Attachment(attachment));
}
message.Priority = MailPriority.High;
message.Body = Template;
message.AlternateViews
.Add(AlternateView
.CreateAlternateViewFromString(ViewContext.ToString(), new ContentType("text/html")));
message.IsBodyHtml = true;
new SmtpClient(MailServerIp)
{
Port = 25,
UseDefaultCredentials = true
}.Send(message);
}
catch (Exception e)
{
Logger.FatalException("Error sending email:", e);
}
finally
{
message.Dispose();
}
}
public override string ToString()
{
return string.Format("To: {0}, From: {1}, Template: {2}, ViewContext: {3}, Attachments: {4}, Subject: {5}", To, From, Template, ViewContext, Attachments, Subject);
}
}
在这里,我已根据您的需求添加了更改版本
public static class AsyncExecuter
{
private static readonly ThreadLocal<List<Action>> TasksToExecute =
new ThreadLocal<List<Action>>(() => new List<BackgroundTask>());
public static Action<Exception> ExceptionHandler { get; set; }
public static void ExecuteLater(BackgroundTask task)
{
TasksToExecute.Value.Add(task);
}
public static void Discard()
{
TasksToExecute.Value.Clear();
}
public static void StartExecuting()
{
var value = TasksToExecute.Value;
var copy = value.ToArray();
value.Clear();
if (copy.Length > 0)
{
Task.Factory.StartNew(() =>
{
foreach (var backgroundTask in copy)
ExecuteTask(backgroundTask);
}, TaskCreationOptions.LongRunning)
.ContinueWith(task =>
{
if (ExceptionHandler != null)
ExceptionHandler(task.Exception);
}, TaskContinuationOptions.OnlyOnFaulted);
}
}
public static void ExecuteTask(Action task)
{
task.Invoke();
}
}