Note that there are some explanatory texts on larger screens.

plurals
  1. POUpdate progress bar in main thread in MVVM
    text
    copied!<p>In my application I perform a long operation and I want to show a progress of the operation. In long operation I use 3rd-party dll. Unfortunately that dll doesn't support calls from non-main thread. So I cannot use another thread to start my process.</p> <p>I found a way how to update progress bar in the main thread using Dispather. At first I wrote a simple WPF application and wrote simple method in code-behind.</p> <pre><code>private void ButtonBase_OnClick(object sender, RoutedEventArgs e) { for (int i = 0; i &lt;= 100; i++) { Dispatcher.Invoke(DispatcherPriority.Loaded, (Action)(() =&gt; { pb.Value = i; })); Thread.Sleep(10); } } </code></pre> <p>This code works fine. I see the progress in my window. But the problem I use MVVM, so I cannot use this method.</p> <p>To solve my problem I created AttachedProperty</p> <pre><code>internal class ProgressBarAttachedBehavior { public static readonly DependencyProperty ValueAsyncProperty = DependencyProperty.RegisterAttached("ValueAsync", typeof (double), typeof (ProgressBarAttachedBehavior), new UIPropertyMetadata(default(double), ValueAsyncChanged)); private static void ValueAsyncChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var pb = d as ProgressBar; if (pb == null) { return; } var dispatcher = d.Dispatcher; //if (dispatcher == null || dispatcher.CheckAccess()) //{ // pb.Value = (double) e.NewValue; //} //else { DispatcherFrame frame = new DispatcherFrame(true); var dispatcherOperation = dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =&gt; { pb.Value = (double)e.NewValue; frame.Continue = false; }) ); Dispatcher.PushFrame(frame); } } public static void SetValueAsync(ProgressBar progressBar, double value) { progressBar.SetValue(ValueAsyncProperty, value); } public static double GetValueAsync(ProgressBar progressBar) { return (double)progressBar.GetValue(ValueAsyncProperty); } </code></pre> <p>In XAML I wrote</p> <pre><code>&lt;ProgressBar tesWpfAppMvvm:ProgressBarAttachedBehavior.ValueAsync="{Binding Progress}"/&gt; </code></pre> <p>And my ViewModel code</p> <pre><code>class Workspace1ViewModel : WorkspaceViewModel { private ICommand _startCommand; private double _progress; public ICommand StartCommand { get { if (_startCommand == null) { _startCommand = new RelayCommand(Start); } return _startCommand; } } private void Start() { for (int i = 0; i &lt;= 100; i++) { Progress = i; Thread.Sleep(20); } } public double Progress { get { return _progress; } set { _progress = value; RaisePropertyChanged(() =&gt; Progress); } } } </code></pre> <p>The code works fine. Long process is run in the main-thread and I see the progress in the window.</p> <p>But the issue, that when I change my Active ViewModel to another model, I get error:</p> <pre><code>Cannot perform this operation while dispatcher processing is suspended. </code></pre> <p>I tried find the solution everywhere but couldn't. Everywhere the solution is run log process in separate thread.</p> <p>Please tell me where is my mistake and how to solve my issue.</p> <p>You may download demo project to reproduce the issue <a href="https://dl.dropboxusercontent.com/u/62538318/Code/TesWpfAppMVVM.zip" rel="nofollow">here</a></p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload