Question

I am using below code to show the progress bar status in WPF (MVVM) app which is basically on a thread however if I am putting on a dispatcher thread it's status not being updated on UI.

With Thread:

Main()
    {


      Thread LoadApp = new Thread(MyData);
            LoadApp.Start();
    }

public void MyData()
{
        ProgMessage = "10%";
        ProgValue = 10;
        var varAction = new List<Func<object>>();
        varAction .Add(() => (MainViewMode1)ViewModel1.ViewModel1);
        varAction .Add(() => (MainViewMode2)ViewModel2.ViewModel2);
        varAction .Add(() => (MainViewMode3)ViewModel3.ViewModel3);

        foreach (var action in varAction )
        {
            var obj = action();
            ProgressMessage = // My message from VM
            ProgressBarValue += // My message valuefrom VM;
        }

}

This is working fine but since now I am using dependency property I got the cross threading exception (STA) so I changed the code to:

Main()
{

           Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() =>
            {
               MyData();

            }));

}



 public void MyData()
    {
            ProgMessage = "10%";
            ProgValue = 10;
            var varAction = new List<Func<object>>();
            varAction .Add(() => (MainViewMode1)ViewModel1.ViewModel1);
            varAction .Add(() => (MainViewMode2)ViewModel2.ViewModel2);
            varAction .Add(() => (MainViewMode3)ViewModel3.ViewModel3);

            foreach (var action in varAction )
            {
                var obj = action();
                ProgressMessage = // My message from VM
                ProgressBarValue += // My message valuefrom VM;
            }

   }

Now I get rid of threading error but its not updating the progress bar status on UI ?

Any clue on this ?

Was it helpful?

Solution

UI elements will not update until you relinquish control of the dispatcher thread. Normally you'd do that by returning back into the event loop, which typically means just returning. But if you've got a load of work to do in a loop, then that's not really practical. So in general, you don't want to do this sort of work on the UI thread.

When you say you're "using dependency property" do you mean that your ViewModel class's properties are dependency properties? You might want to reconsider that, because it prevents multi-threaded use. If you make them ordinary, non-auto properties, you can still use data binding to connect them to the UI. To get the UI to update when the properties change, you'll need to implement INotifyPropertyChanged, and you make your properties raise change notifications, then you'll find that you're able to do work on a worker thread as in your first example, and if you bind those properties to the UI, you won't get threading exceptions, and it'll update just fine.

(WPF's data binding system detects when a bound property changes on a thread other than the UI thread, and automatically arranges to update the UI from the correct thread. But you can't use DPs in your VM if you want to take advantage of this, because DPS have thread affinity.)

The DoEvents style approach someone else proposed does work but it is problematic and I avoid it. It enables re-entrancy - if the user interacts with your app in a way that causes event handlers to run, they will run inside that call to Dispatcher.PushFrame. This is not necessarily a problem, but it's very easy to get into a mess.

Yet another approach would be to do the work on the worker thread, but to use Dispatcher.Invoke to call a method that updates the ProgressMessage and ProgressBarValue properties. That way, your work occurs on a worker thread (leaving the UI thread free to update), but you'll be updating those DPs on the UI thread, which avoids the error.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top