为什么我的异步任务冻结AI动画GUI中的? [英] Why is my asynchronous task freezing AI animations in the GUI?

查看:158
本文介绍了为什么我的异步任务冻结AI动画GUI中的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的code相pretty很像以下内容:

 命名空间CloudKey
{
///<总结>
///为的Page1.xaml交互逻辑
///< /总结>
公共部分类第1页:第
{
    公共第1页()
    {
        的InitializeComponent();
    }    私人异步无效button_Click(对象发件人,RoutedEventArgs E)
    {
        //开始加载动画
        Loading.Visibility = Visibility.Visible;        //运行任务
        等待Task.Run(()=> LoginCheck());
    }    异步无效LoginCheck()
    {
        等待Dispatcher.InvokeAsync(
                ()=>
                {
                    InitialSessionState ISS = InitialSessionState.CreateDefault();
                    StringBuilder的SS =新的StringBuilder();
                    ss.AppendLine(一些code在这里)
                    使用(运行空间运行空间= RunspaceFactory.CreateRunspace(ISS))
                    {
                        收集和LT; PSObject>结果= NULL;
                        尝试
                        {
                            runspace.Open();
                            管道管道= runspace.CreatePipeline();
                            pipeline.Commands.AddScript(ss.ToString());
                            结果= pipeline.Invoke();                        }
                        赶上(异常前)
                        {
                            results.Add(新PSObject((对象)ex.Message));
                        }
                        最后
                        {
                            runspace.Close();
                            Loading.Visibility = Visibility.Hidden;
                            如果//一些东西
                            {
                                //做一些事情
                            }
                            其他
                            {
                                //做一些其他的事情
                            }
                        }
                    }
                });
    }
  }
}

我也试过

 异步无效LoginCheck()
{
    等待Dispatcher.Invoke(()=> {//东西});
}

具有相同的结果。我没有真正知道什么是两者之间的区别是...

任务正常运行无论哪种方式,但动画开始,然后尽快任务开始冻结。 :/我应该怎么做,使这项工作我就打算与加载动画动画整个功能的方式

编辑:

我要补充一点,我试图删除

 等待Dispatcher.InvokeAsync(
            ()=> {});

和留在机智的函数的其余部分,不过,我得到以下错误,当我这样做的:

 调用线程,因为不同的线程拥有它无法访问该对象。


解决方案

我认为这需要的所有是删除

 等待Dispatcher.InvokeAsync(()=> {};

周围code。看着为Dispatcher.InvokeAsync文档,它说异步的Dispatcher关联的线程上执行指定委托。 (<一href=\"https://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.invokeasync(v=vs.110).aspx\"相对=nofollow称号=源>来源)分派器链接到页面与页面的线程所以它的执行UI线程上的code,仍与其关联。除去周围的函数调用应该使code只是在不同的线程运行,因为你已经叫Task.Run(),以在不同的线程中运行它。

编辑:错过了在那里加载得到改变的部分,这是由UI线程所拥有。下面是说明了这个问题更好的实际code样品:<​​/ P>

 异步无效LoginCheck()
{
    InitialSessionState ISS = InitialSessionState.CreateDefault();
    StringBuilder的SS =新的StringBuilder();
    ss.AppendLine(一些code在这里)
    使用(运行空间运行空间= RunspaceFactory.CreateRunspace(ISS))
    {
        收集和LT; PSObject&GT;结果= NULL;
        尝试
        {
            runspace.Open();
            管道管道= runspace.CreatePipeline();
            pipeline.Commands.AddScript(ss.ToString());
            结果= pipeline.Invoke();        }
        赶上(异常前)
        {
            results.Add(新PSObject((对象)ex.Message));
        }
        最后
        {
            runspace.Close();
            Dispatcher.InvokeAsync(()=&GT; {
                Loading.Visibility = Visibility.Hidden;
            });            如果//一些东西
            {
                //做一些事情
            }
            其他
            {
                //做一些其他的事情
            }
        }
    }
}

由于Loading.Visibility是一个UI元素,它是由UI线程拥有。所以围绕这一点与Dispatcher.Invoke(呼叫)将改变从UI线程的价值,同时还执行其他线程的DB调用如上所述。

My code looks pretty much like the following:

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
                            }
                        }
                    }
                });
    }
  }
}

I've also tried

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

with the same result. I'm not actually sure what the difference between the two are...

The task runs correctly either way, but the animation starts then freezes as soon as the task begins. :/ What should I do to make this work the way I intend it to with the loading animation animating throughout the functions?

EDIT:

I should add that I attempted to remove the

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

and leave the rest of the function in tact, however, I get the following error when I do so:

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

解决方案

I think all that's needed is to remove the

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

surrounding the code. Looking at the Documentation for Dispatcher.InvokeAsync, it says "Executes the specified delegate asynchronously on the thread the Dispatcher is associated with." (source) The Dispatcher linked to a page is associated with the page's thread, so it's executing the code on the UI thread, still. Removing that surrounding function call should make the code simply run on a different thread because you already called Task.Run() to run it on a different thread.

EDIT: Missed the part where Loading got changed, which is owned by the UI thread. Here's an actual code sample that illustrates the issue better:

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

Because Loading.Visibility is a UI Element, it's owned by the UI thread. So surrounding just that call with Dispatcher.Invoke() will change that value from the UI Thread, while still executing the db calls on the other thread as explained above.

这篇关于为什么我的异步任务冻结AI动画GUI中的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆