Wpf MVVM raiseexecutechanged阻止进度条运行 [英] Wpf MVVM raiseexecutechanged prevents progressbar functioning

查看:82
本文介绍了Wpf MVVM raiseexecutechanged阻止进度条运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的WPF MVVM应用程序中确实需要一个Progressbar

以常规方式使用它,只需在任何步骤更新绑定值,导致Progressbar不更新。

我找到了这篇文章并自然而然地尝试将它应用到我的解决方案中。

BackgroundWorker and ProgressBar演示 [ ^ ]



但是背景工作者提出了他自己的问题:

我得到一个异常说明我的变量(不是Progressbarvalue,似乎得到了正确地更新)正在调用RaiseExecuteChanged时由另一个线程使用。



非常感谢您的帮助!在此先感谢。



我尝试过:



I do need a Progressbar in my WPF MVVM application
Using it the regular way and just updating the bound Value at any step results in the Progressbar not updating.
I found this article and naturally tried applying it to my solution
BackgroundWorker and ProgressBar demo[^]

But the Backgroundworker provides his own problem:
I get an exception stating my variables (NOT the Progressbarvalue, that seems to get updated properly) are in use by another thread when RaiseExecuteChanged is being called.

Your help would be very much appreciated! Thanks in advance.

What I have tried:

//The Command I use
public class BaseCommand : ICommand
    {
        /// <summary>
        /// Specifys the conditions to enable the command
        /// </summary>
        /// <param name="parameter"></param>
        /// <returns></returns>
        public virtual bool CanExecute(object parameter)
        {
            return false;
        }

        public event EventHandler CanExecuteChanged;

        /// <summary>
        /// Specifys what should happen if the command is being called
        /// </summary>
        /// <param name="parameter"></param>
        public virtual void Execute(object parameter)
        {
        }

        public void RaiseExecuteChanged(object sender, EventArgs e)
        {
            if (CanExecuteChanged != null)
                CanExecuteChanged(sender, e);
        }
    }

private CommandErrorAnalysis commandErrorAnalysis;
        public CommandErrorAnalysis CommandErrorAnalysis
        {
            get
            {
                return commandErrorAnalysis;
            }
        }

//How I initialise my Command in the ViewModel

            commandErrorAnalysis = new CommandErrorAnalysis(this);
            addToPropertyChanged(CommandErrorAnalysis);

//My Commands Execute (It's called CommandErrorAnalysis and only gets it's calling ViewModel as parameter in its Constructor)
public override void Execute(object parameter)
        {
            bw = new BackgroundWorker();
            bw.WorkerReportsProgress = true;
            bw.DoWork += new DoWorkEventHandler(doProgress);
            bw.RunWorkerAsync();
        }

//And finally the actual work being done
private void doProgress(object sender, DoWorkEventArgs e)
        {
            bw.ReportProgress(10); //Can be stepped over
            vma.CommandSecurity.Execute(null); //Calls a RaiseExecuteChanged and throws the Exception
        }

//This is the line throwing the exception, with vm being the ViewModel I use the Command from
vm.ColorSecurity = Brushes.Green;

//The Property itself
private SolidColorBrush colorSecurity;
        public SolidColorBrush ColorSecurity
        {
            get
            {
                return colorSecurity;
            }
            set
            {
                colorSecurity = value;
                this.onPropertyChanged("ColorSecurity");
            }
        }

//And finally the actual point of the Exception, which is inside BaseCommand
public void RaiseExecuteChanged(object sender, EventArgs e)
        {
            if (CanExecuteChanged != null)
                CanExecuteChanged(sender, e); //<- This is where Visual Studio stops and shows the Exception. 
//I do have the english Version of VS, yet the Exception is german. I'll translate
//"Der aufrufende Thread kann nicht auf dieses Objekt zugreifen, da sich das Objekt im Besitz eines anderen Threads befindet."
//The calling thread cannot use this object, as the object belongs to a different thread.
        }

推荐答案

总是同样的问题这种功能......你从另一个线程设置一个UI属性 - 所以只调整正确的调用(UI线程)。我在我的ViewModels中使用
Always the same problem with this kind of functionality... You set a UI property from another thread - so just marshal the call to the correct one (the UI thread). I use a
Dispatcher dispatcherUIThread

变量,我使用当前的Application Dispatcher(

Variable in my ViewModels that I fill (on app initialization) with the current Application Dispatcher (

App.Current.Dispatcher



因此,您的有问题的行应该更改为类似


So your problematic line should be changed to something like this

dispatcherUIThread.Invoke(() => vm.ColorSecurity = Brushes.Green);





我尝试将我的后台工作设计为独立的可能来自UI,所以我不在异步方法中使用例如



I try to design my background work as independend as possible from the UI so I don't use e.g.

sometextbox.Text 

,但是使用变量进行输入,并且只编组最终输出,错误信息或进度返回到UI线程。(请记住,BackgroundWoker通过在起始线程上调用Completed来进行一些自动编组 - 你可以对你的RaiseExecuteChanged做同样的事情......

inside async methods, but use variables for input, and only marshal final output, error information or progress back to the UI thread. (Keep in mind that BackgroundWoker does some Auto marshalling by calling Completed on the starting thread - you could do the same with your RaiseExecuteChanged...


这篇关于Wpf MVVM raiseexecutechanged阻止进度条运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆