WPF UI 上的进度条未更新

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20857279/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 10:21:11  来源:igfitidea点击:

Progress bar not getting updated on WPF UI

c#wpfmultithreadingdependency-propertiesdispatcher

提问by user2519971

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.

我正在使用下面的代码来显示 WPF(MVVM)应用程序中的进度条状态,该应用程序基本上位于一个线程上,但是如果我将其置于调度程序线程上,则其状态不会在 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:

这工作正常但因为现在我使用依赖属性我得到了跨线程异常(STA)所以我将代码更改为:

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 ?

现在我摆脱了线程错误,但它没有更新 UI 上的进度条状态?

Any clue on this ?

关于这个的任何线索?

回答by Ian Griffiths

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.

在您放弃对调度程序线程的控制之前,UI 元素不会更新。通常你会通过返回到事件循环来做到这一点,这通常意味着只是返回。但是,如果您有大量工作要在循环中完成,那么这并不实用。所以一般来说,你不想在 UI 线程上做这种工作。

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.

当你说你“使用依赖属性”时,你的意思是你的 ViewModel 类的属性是依赖属性?您可能需要重新考虑这一点,因为它会阻止多线程使用。如果您将它们设为普通的、非自动的属性,您仍然可以使用数据绑定将它们连接到 UI。要在属性更改时更新 UI,您需要实现INotifyPropertyChanged,并使您的属性引发更改通知,然后您会发现您可以像第一个示例一样在工作线程上工作,如果将这些属性绑定到 UI,则不会出现线程异常,并且它会更新得很好。

(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.)

(WPF 的数据绑定系统会检测到绑定属性在 UI 线程以外的线程上何时发生更改,并自动安排从正确的线程更新 UI。但是如果您想利用这一点,则不能在 VM 中使用 DP ,因为 DPS 具有线程关联性。)

The DoEventsstyle 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.

DoEvents其他人提出的风格方法确实有效,但它是有问题的,我避免了它。它支持重入 - 如果用户以导致事件处理程序运行的方式与您的应用程序交互,它们将在对Dispatcher.PushFrame. 这不一定是问题,但很容易陷入混乱。

Yet another approach would be to do the work on the worker thread, but to use Dispatcher.Invoketo call a method that updates the ProgressMessageand ProgressBarValueproperties. 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.

另一种方法是在工作线程上完成工作,但Dispatcher.Invoke用于调用更新ProgressMessageProgressBarValue属性的方法。这样,您的工作发生在工作线程上(让 UI 线程可以自由更新),但您将在 UI 线程上更新这些 DP,从而避免了错误。