Click here to Skip to main content
15,918,109 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
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:

C#
//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.
        }
Posted
Updated 30-Jun-16 4:08am

1 solution

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
C#
Dispatcher dispatcherUIThread
Variable in my ViewModels that I fill (on app initialization) with the current Application Dispatcher (
C#
App.Current.Dispatcher

So your problematic line should be changed to something like this
C#
dispatcherUIThread.Invoke(() => vm.ColorSecurity = Brushes.Green);


I try to design my background work as independend as possible from the UI so I don't use e.g.
C#
sometextbox.Text 
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...
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900