【问题标题】:Why is my asynchronous task freezing AI animations in the GUI?为什么我的异步任务会冻结 GUI 中的 AI 动画?
【发布时间】:2016-05-10 23:25:29
【问题描述】:

我的代码如下所示:

namespace CloudKey
{
/// <summary>
/// Interaction logic for Page1.xaml
/// </summary>
public partial class Page1 : Page
{
    public Page1()
    {
        InitializeComponent();
    }

    private async void button_Click(object sender, RoutedEventArgs e)
    {
        //Begin Loading animation
        Loading.Visibility = Visibility.Visible;

        //Run Task
        await Task.Run(() => LoginCheck());
    }

    async void LoginCheck()
    {
        await Dispatcher.InvokeAsync(
                () =>
                {
                    InitialSessionState iss = InitialSessionState.CreateDefault();
                    StringBuilder ss = new StringBuilder();
                    ss.AppendLine("some code here")
                    using (Runspace runspace = RunspaceFactory.CreateRunspace(iss))
                    {
                        Collection<PSObject> results = null;
                        try
                        {
                            runspace.Open();
                            Pipeline pipeline = runspace.CreatePipeline();
                            pipeline.Commands.AddScript(ss.ToString());
                            results = pipeline.Invoke();

                        }
                        catch (Exception ex)
                        {
                            results.Add(new PSObject((object)ex.Message));
                        }
                        finally
                        {
                            runspace.Close();
                            Loading.Visibility = Visibility.Hidden;
                            if //some stuff
                            {
                                //do some things
                            }
                            else
                            {
                                //do some other things
                            }
                        }
                    }
                });
    }
  }
}

我也试过

Async void LoginCheck()
{
    await Dispatcher.Invoke (() => {//Stuff});
}

结果相同。我实际上不确定两者之间的区别是什么......

无论哪种方式,任务都会正确运行,但动画会在任务开始后立即冻结。 :/ 我应该怎么做才能使这项工作按照我想要的方式工作,加载动画在整个函数中设置动画?

编辑:

我应该补充一点,我试图删除

await Dispatcher.InvokeAsync(
            () =>{});

并保留函数的其余部分,但是,当我这样做时,我收到以下错误:

The calling thread cannot access this object because a different thread owns it.

【问题讨论】:

  • 你告诉一个新的线程池线程除了告诉 UI 线程执行一堆代码之外什么都不做。因此,所有代码都在 UI 线程中运行是意料之中的。如果要在 UI 线程之外运行代码,则需要在 UI 线程之外实际运行代码。
  • 我不确定我是否理解...你能举个例子吗?
  • 你提供了一个例子。您在 UI 线程中运行所有代码并抱怨您的所有代码都在 UI 线程中运行。

标签: c# wpf visual-studio asynchronous dispatcher


【解决方案1】:

我认为只需要删除

await Dispatcher.InvokeAsync(() => { };

围绕代码。查看 Dispatcher.InvokeAsync 的文档,它说“在与 Dispatcher 关联的线程上异步执行指定的委托”。 (source) 链接到页面的 Dispatcher 与页面的线程相关联,因此它仍然在 UI 线程上执行代码。删除周围的函数调用应该会使代码简单地在不同的线程上运行,因为您已经调用了 Task.Run() 以在不同的线程上运行它。

编辑:错过了加载更改的部分,该部分归 UI 线程所有。这是一个更好地说明问题的实际代码示例:

async void LoginCheck()
{
    InitialSessionState iss = InitialSessionState.CreateDefault();
    StringBuilder ss = new StringBuilder();
    ss.AppendLine("some code here")
    using (Runspace runspace = RunspaceFactory.CreateRunspace(iss))
    {
        Collection<PSObject> results = null;
        try
        {
            runspace.Open();
            Pipeline pipeline = runspace.CreatePipeline();
            pipeline.Commands.AddScript(ss.ToString());
            results = pipeline.Invoke();

        }
        catch (Exception ex)
        {
            results.Add(new PSObject((object)ex.Message));
        }
        finally
        {
            runspace.Close();
            Dispatcher.InvokeAsync(() => {
                Loading.Visibility = Visibility.Hidden;
            });

            if //some stuff
            {
                //do some things
            }
            else
            {
                //do some other things
            }
        }
    }
}

因为 Loading.Visibility 是一个 UI 元素,所以它归 UI 线程所有。因此,仅使用 Dispatcher.Invoke() 围绕该调用将从 UI 线程更改该值,同时仍如上所述在另一个线程上执行 db 调用。

【讨论】:

  • 我得到一个错误:调用线程无法访问这个对象,因为另一个线程拥有它。
  • @NickG 我发现了问题并相应地编辑了答案。没有注意到 Loading.Visibility 调用。
  • 调试后是因为我从那个工作线程调用了一个 UI 函数。你的建议奏效了!
  • 很好,很高兴它成功了。我记得在我刚接触 WPF 时也遇到过这些问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-21
  • 2014-09-14
  • 1970-01-01
相关资源
最近更新 更多