【问题标题】:Adding UserControls to Grid Asynchronously [duplicate]将用户控件添加到网格异步[重复]
【发布时间】:2021-09-15 12:13:02
【问题描述】:

我正在使用 WPF 应用程序,并且在应用导航时遇到问题,屏幕冻结,所以我想实现异步

我的导航方法:我创建一个网格并将用户控件添加到该网格的 children 属性 由于我在许多不同的用户控件上有这么多 UI 元素,它会冻结应用程序

我想在加载窗口时添加一个异步用户控件,我的想法是使用 async await 关键字,但显然我使用错误,我研究过,不明白为什么建议使用调度程序甚至在有异步等待之后,所以我想按照这种方式(异步/等待)

这只是真实交易的一个示例问题

这是代码

private async void grid1_Loaded(object sender, RoutedEventArgs e)
    {
        txtb1.Text = "";

        var watch = System.Diagnostics.Stopwatch.StartNew();

        await gy();

        watch.Stop();
        var elapsedtm = watch.ElapsedMilliseconds;

        txtb1.Text += $"TOTAL TIME {elapsedtm} \n\n\n";
    }

    private async Task gy() 
    {
        ////////////
        
        Y1 child1 = new Y1();
        await Task.Run(() => grid1.Children.Add(child1));
        
        ///////////
    }

【问题讨论】:

  • 您只能在创建 grid1 的线程中访问grid1.Children,即不能从任务操作中访问。也许使用 DispatcherTimer 在块中添加子元素。
  • 通常向 UI 添加元素很快。通常是一些需要时间的数据处理。或者您是说您正在创建一些 UI 元素,而数据处理可以忽略不计,这会降低您的应用程序的速度?
  • @Clemens 那么你是说使用 Async 和 await 是行不通的,而 dispathcher.begininvoke 就是这样,我知道如何使用 Dispatcher 执行它们我想学习异步方式
  • @Enigmativity 好吧,我正在使用一个名为 MaterialDesignforXAML 的库,我在用户控件中使用这些 UI 元素,并将这些用户控件添加到网格中,在添加了这些众多的用户控件之后,我只是根据几个按钮点击事件
  • 不,我不是这么说的。 Async/await 和 Dispatcher 不是相互排斥的。两者都可以很好地协同工作。如果您要访问具有线程关联性的对象 - 例如UI 元素 - 从创建它的线程以外的线程,您必须通过对象的 Dispatcher 或在同一线程中创建的 Progress 实例来执行此操作。请注意,Task.Run 通常在与线程池不同的线程上运行。

标签: c# .net wpf multithreading async-await


【解决方案1】:
        private async void grid1_Loaded(object sender, RoutedEventArgs e)
        {
            txtb1.Text = "";

            var watch = System.Diagnostics.Stopwatch.StartNew();

            //Asynchronous execution of the "gy" method in the UI thread.
            await Dispatcher.InvokeAsync(gy);

            watch.Stop();
            var elapsedtm = watch.ElapsedMilliseconds;

            txtb1.Text += $"TOTAL TIME {elapsedtm} \n\n\n";
        }

        // This method can only be called on the main UI thread.
        private void gy()
        {
            ////////////

            UIElement child1 = new Y1();
           grid1.Children.Add(child1);

            ///////////
        }

如果 gy 方法中有一些长期操作不使用 UI 元素,并且您需要将主 UI 线程从它们的执行中释放出来,那么这个选项:

        private async void grid1_Loaded(object sender, RoutedEventArgs e)
        {
            txtb1.Text = "";

            var watch = System.Diagnostics.Stopwatch.StartNew();

            
            await gy();

            watch.Stop();
            var elapsedtm = watch.ElapsedMilliseconds;

            txtb1.Text += $"TOTAL TIME {elapsedtm} \n\n\n";
        }

        private async Task gy()
        {
            // Here's some lengthy code, but in which there are no calls to UI elements.
            ////////////

            await grid1.Dispatcher.BeginInvoke(new Action(() =>
             {
                 UIElement child1 = new Label() { Content = "Hello" };
                 grid1.Children.Add(child1);
             }));

            ///////////
            // Here's some lengthy code, but in which there are no calls to UI elements.
        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-07-03
    • 2021-02-15
    • 1970-01-01
    • 2017-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多