tags:

views:

74

answers:

2

I am trying to reuse a UserControl and also borrow some logic that keeps track of progress. I'll try and simplify things. MyWindow.xaml includes a MyUserControl. MyUserControl has its own progress indicator (Formatting in progress..., Copying files..., etc.) and I'd like to mirror this progress somewhere in the MyWindow form. But, the user control has some logic I don't quite understand. I've read and read but I still don't understand the Dispatcher. Here's a summary of the logic in the user control that updates the progress.

this.Dispatcher.Invoke(DispatcherPriority.Input, (Action)(() =>
{
   DAProgressIndicator = InfiniteProgress.AddNewInstanceToControl(StatusGrid, new SolidColorBrush(new Color() { A = 170, R = 128, G = 128, B = 128 }), string.Empty);
                DAProgressIndicator.Message = MediaCardAdminRes.ActivatingCard;
                ActivateInProgress = true;
}));

I thought I'd be smart and add an event to MyUserControl that would be called in the ActivateInProgress property set logic.

   public bool ActivateInProgress 
   {
      get
      {
         return _activateInProgress;
      }
      set
      {
         _activateInProgress = value;
         if (ActivateInProgressHandler != null)
         {
            ActivateInProgressHandler(value);
         }
      }
   }

I'm setting the ActivateInProgressHandler within the MyWindow constructor to the following method that sets the view model property that is used for the window's own progress indicator.

private void SetActivation(bool activateInProgress)
{
   viewModel.ActivationInProgress = activateInProgress;
}

However, the window's progress indicator never changes. So, I'm convinced that the Dispatcher.Invoke is doing something that I don't understand. If I put a message box inside the SetActivation method, the thread blocks and the window's progress indicator is updated. I understand basic threads but this whole Dispatcher thing is new to me. What am I missing?

UPDATE: It seems to be working now. It turns out the progress was being updated so fast that it never got shown on the screen. But, I still would like to understand why the Dispatcher.Invoke was done (this was existing code that I didn't write). Why aren't the action contents done in line with the rest of the *.xaml.cs code?

+1  A: 

Your last paragraph mentions threads twice, which raises the possibility that there are one or more background threads. But since you didn't mention what threads exist in the application, how they are created, how they interact, etc, I'll assume for the moment there is only one thread.

If the UI thread is the only thread, the problem is obvious: Your UI thread is busy running the task in progress, and doesn't take time to render the updated UI. If that's the problem, this will probably fix it:

viewModel.ActivationInProgress = activateInProgress; 
Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle,
                       new Action(() => {}));

The BeginInvoke forces all Dispatcher operations above input priority to complete before the current thread continues.

Ray Burns
A: 

The Dispatcher works on a queue. So it could be that the UI thread is blocking. You add more work in the queue via the Dispatcher but it will never get executed because the UI thread is blocking.

Maybe try this:

DispatcherFrame _frame = new DispatcherFrame();
Dispatcher.PushFrame(_frame);

This will put your work infront of the work already on the queue. So the UI thread will do the work and then block again.

Marthinus