执行任务在从其他任务引发的事件运行时冻结GUI,但不从Button.Click中冻结

时间:2013-12-09 14:13:48

标签: c# task-parallel-library task

我在一个单独的项目中有一些任务可以异步执行。 这一切都按预期工作了几个月了:

  • 开始时会出现“已启动”事件,因此GUI可以启动 忙碌的指标。
  • 最后(或发生异常时)会引发“结束”事件 因此GUI可以停止忙碌指示器并处理内容。

但是一项新要求规定我必须在编程后直接阅读该版本,而无需任何用户交互。

我的第一个想法是从编程的“结束”事件中调用ReadVersion。 但是,这样做时,UI会冻结。 busyindicator挂起“编程”状态,并且在读取版本之前不能移动窗口。 从按钮调用ReadVersion时。单击不会冻结GUI。

ProjectLogic:

protected void ProgramImage()
{
    this.OnProgrammingStarted(new EventArgs());
    this.taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
    Task.Factory.StartNew(this.ProgramImageAsync)
                .ContinueWith(
                            t =>
                            {
                                if (t.IsFaulted)
                                {
                                    this.TaskExceptionHandlerProgramming(t);
                                }
                                else
                                {
                                    this.ProgramImageAsyncDone();
                                }
                            },
                            this.taskScheduler);
}


public void ReadVersion()
{
    this.OnVersionReadingStarted(new EventArgs());
    this.taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
    Task<string>.Factory.StartNew(ReadVersionAsync).ContinueWith(
        t =>
            {
                if (t.IsFaulted)
                {
                    this.TaskExceptionHandlerVersionReading(t);
                }
                else
                {
                    this.ReadVersionAsyncDone(t.Result);
                }
            },
                this.taskScheduler);
}

GUI:

private void OnProgrammingExecuted(object sender, WorkExecutedEventArgs e)
{
    if (e.Error != null)
    {
        // Logging + messagebox
        this.BiProgramming.IsBusy = false;
        this.Restart();
        return;
    }

    if (!e.Success)
    {
        // Logging + messagebox
        this.BiProgramming.IsBusy = false; 
        this.Restart();
        return;
    }

    this.BiProgramming.IsBusy = false;  // Stops busyindicator

    BL.ReadVersion();  // Window freezes and busyIndicator stays visible.
}


private void BtnReadVersionClick(object sender, RoutedEventArgs e)
{
    BL.ReadVersion(); // works as expected
}

修改

OnProgrammingExecuted是从ProgramImageAsyncDone内引发事件时执行的方法。

从UI线程调用方法ProgramImage。 如果我没有弄错的话,这意味着TaskSheduler.FromCurrentSynchronizationContext可以确保{-1}}(或ProgramImageAsyncDone)在UI线程上运行。

事先没有引起任何问题,这加强了我的意见。

问题在于我必须添加的行:对TaskExceptionHandlerProgramming的调用。 添加此行后,UI处于冻结状态。 但是从按钮调用此方法。单击不会冻结UI。

1 个答案:

答案 0 :(得分:0)

在搜索解决方案时,我遇到了Task.Run vs Task.Factory.StartNew,我使用Task.Run重写了我的代码,看看这是否解决了我的问题。 显然它确实如此。

更改了代码:

protected void ProgramImage()
{
    this.OnProgrammingStarted(new EventArgs());
    this.taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
    Task.Run(() => this.ProgramImageAsync()).ContinueWith(
                            t =>
                            {
                                if (t.IsFaulted)
                                {
                                    this.TaskExceptionHandlerProgramming(t);
                                }
                                else
                                {
                                    this.ProgramImageAsyncDone();
                                }
                            },
                            this.taskScheduler);
}


public void ReadVersion()
{
    this.OnVersionReadingStarted(new EventArgs());
    Task.Run(() => ReadVersionAsync()).ContinueWith(
        t =>
        {
            if (t.IsFaulted)
            {
                this.TaskExceptionHandlerVersionReading(t);
            }
            else
            {
                this.ReadVersionAsyncDone(t.Result);
            }
        },
                this.taskScheduler);
}