繁体   English   中英

从其他任务引发的事件(而不是从Button.Click)运行时,执行任务会冻结GUI。

[英]Executing Task freezes GUI when running from event raised by other Task, but not from Button.Click

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

  • 在开始时会引发“开始”事件,因此GUI可以启动繁忙指示器。
  • 最后(或发生异常时),将引发“ Ended”事件,以便GUI可以停止忙碌指示器并处理内容。

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

我的第一个想法是从编程的“ Ended”事件中调用ReadVersion 但是,这样做时,UI会冻结。 忙碌指示器挂在“正在编程”状态,在读取版本之前无法移动窗口。 通过ReadVersion调用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确保ProgramImageAsyncDone (或TaskExceptionHandlerProgramming )在UI线程上运行。

它以前没有引起任何问题,这一事实增强了我的看法。

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

在寻找解决方案时,我遇到了Task.Run与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);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM