0

I am working with a WPF application and I am facing problems while applying Navigation, the screen freezes , So I want to achieve Asynchronicity

My method of navigation : I create a grid and add User controls to the children property of that grid and since I have so many UI elements on numerous different User controls it freezes the Application

I want to add A user control asynchronous on when the window is loaded, My idea is to use the async await keywords but obviously I am using them incorrectly, I have researched and do not understand why it is suggested to use dispatcher even after there being async await so I wanted to follow that way (async/await)

This is just a sample problem of the real deal

this is the code

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));
        
        ///////////
    }
  • 2
    You can only access `grid1.Children` in the thread in which grid1 was created, i.e. not from a Task Action. Maybe use a DispatcherTimer to add child elements in chunks. – Clemens Jul 04 '21 at 10:38
  • Usually adding elements to the UI is quick. It's often some data processing that takes time. Or are you saying that you're creating some many UI elements, with negligible data process, that's slowing down your app? – Enigmativity Jul 04 '21 at 12:40
  • @Clemens So are you saying using Async and await isnt going to work and dispathcher.begininvoke is the way, I know how to execute them using Dispatcher I wanted to learn the async way – caroldavies42 Jul 04 '21 at 13:58
  • @Enigmativity Well i am using a library called MaterialDesignforXAML, I ab using these UI elements in a user control, and adding those usercontrol to a grid, after adding these numerous usercontrols i just shift their visibility based on a few button click events – caroldavies42 Jul 04 '21 at 14:02
  • No, I'm not saying that. Async/await and Dispatcher are not mutually exclusive. Both may well work together. If you are going to access an object with thread affinity - e.g. a UI element - from a thread other than the one in which it was created, you have to do that by means of the object's Dispatcher, or alternatively by a [Progress](https://learn.microsoft.com/en-us/dotnet/api/system.progress-1?view=net-5.0) instance that was created in the same thread. Be aware that Task.Run usually runs on a different thread from a thread pool. – Clemens Jul 04 '21 at 14:40
  • @caroldavies42 - That didn't answer my question. Can you try again? – Enigmativity Jul 05 '21 at 01:19

1 Answers1

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

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

If in the gy method there are some long-term operations without using UI elements and you need to free the main UI thread from their execution, then this option:

        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.
        }
EldHasp
  • 6,079
  • 2
  • 9
  • 24