0

我有遗留代码在 UI 线程上执行一些非常长的操作。我想要做的是显示一个带有消息的进度条并在另一个线程上运行工作。不幸的是,现在我无法访问 VS2012,所以我不能使用async关键字。我编写了一些代码,可以很好地处理 0-1 参数的操作,并且使用Action没有返回值。但是当我尝试调整它以支持 Func 时,我在调用任务和返回 TResult 时遇到了一些问题。附件是我的原始代码,不胜感激。谢谢, 奥马尔

    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
    }
4

1 回答 1

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();
    }
}
于 2013-02-18T09:46:22.337 回答