进度条未在WPF UI上更新

use*_*971 0 c# wpf multithreading dependency-properties dispatcher

我使用下面的代码来显示WPF(MVVM)应用程序中的进度条状态,该应用程序基本上是在一个线程上,但是如果我在调度程序线程上放置它的状态没有在UI上更新.

有线程:

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;
        }
Run Code Online (Sandbox Code Playgroud)

}

这工作正常但是从现在开始我使用依赖属性我得到了交叉线程异常(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;
            }

   }
Run Code Online (Sandbox Code Playgroud)

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

这有什么线索吗?

Ian*_*ths 6

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

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

(WPF的数据绑定系统检测绑定属性何时在UI线程以外的线程上发生更改,并自动安排从正确的线程更新UI.但如果要利用此功能,则无法在VM中使用DP ,因为DPS具有线程亲和力.)

DoEvents其他人提出的风格方法确实有效,但这是有问题的,我避免使用它.它可以实现重新入门 - 如果用户以导致事件处理程序运行的方式与您的应用程序交互,它们将在该调用内部运行Dispatcher.PushFrame.这不一定是个问题,但很容易搞得一团糟.

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