I have a background worker process that starts provisioning a new client for our system. Here is what the DoWork method looks like:
ProvisioningManager manager = new ProvisioningManager(false)
{
};
System.Windows.Application.Current.Dispatcher.Invoke((Action)(() =>
{
this.MaxSteps = manager.MaxProgress;
}));
manager.StatusUpdated += new ProvisioningManager.StatusUpdatedHandler(manager_StatusUpdated);
manager.TaskCompleted += new ProvisioningManager.TaskCompleteHandler(manager_TaskCompleted);
manager.ProvisionClient();
while (!manager.Completed)
{
System.Threading.Thread.Sleep(100 * 60);
}
Basically it creates the manager that handles talking to the different sub-systems which provision the client.
Now I have a status update event and completed event for the provisioning manager. When the TaskCompleted event fires I want to be able to set a property on my display object so that the finish button in the wizard is enabled:
void manager_TaskCompleted(object sender, ProvisioningManager.Task taskType)
{
System.Windows.Application.Current.Dispatcher.Invoke((Action)(() =>
{
this.ProvisioningComplete = true;
}));
}
The XAML for the button looks like this:
<wizard:WizardPage Header="Provisioning Client..."
ShowBack="False"
AllowBack="False"
AllowFinish="{Binding Source={StaticResource ResourceKey=dataObject}, Path=ProvisioningComplete}"
Loaded="Provisioning_Loaded">
</wizard:WizardPage>
This isn’t working. Even though I make sure to hit the dispatcher thread to set the property of the display object it doesn’t actually change the button to enabled until I click on the window. Is this a bug in AvalonWizard or am I not on the correct thread to set an INotifyPropertyChanged? Is there a way to hack this; basically can I programmatically focus the window without the mouse click?
I tired placing that while loop in the DoWork method so that I could use the BackgroundWorker’s completed method:
void provisioningWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
System.Windows.Application.Current.Dispatcher.Invoke((Action)(() =>
{
this.ProvisioningComplete = true;
}));
}
That doesn’t work either. What gives?!
Update
Here is the requested static resource instantiation for the display object:
<Window.Resources>
<ObjectDataProvider x:Key="dataObject" ObjectType="{x:Type winDO:NewClientWizardDO}" />
</Window.Resources>
Update II
Here is the property and property change firer:
public bool ProvisioningComplete
{
get { return this._ProvisioningComplete; }
set
{
this._ProvisioningComplete = value;
this.NotifyPropertyChanged("ProvisioningComplete");
}
}
protected void NotifyPropertyChanged(params string[] propertyNames)
{
if (this.PropertyChanged != null)
{
foreach (string propertyName in propertyNames)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
So I couldn’t find out exactly why I was having this issue. I tried setting focus to the window, the button, etc. I tried multiple ways of letting the view know the viewmodel had updated. Basically every suggestion I could find on the web didn’t work. It almost seems like a bug.
A smarty on my team suggested faking a mouse click on the window. His idea was that since all it took to activate the button was a simple mouse click on the screen then faking one should have the same effect. I thought (and think) that this hack was ridiculous. I did try it out just to see if I could call it a “solution”.
Well, it worked. We had this same problem in another one of our wizards (not AvalonWizard but a homegrown one). I think there has to be some underlying issue with the way the window redraws after a background thread updates objects that are bound to the UI.
Anyhow, the way I found to solve this issue is with the following hack-tastic code.
I’ve tested this when the window is not the active window and when the user leaves the window as selected. The focus method seems to take care of this issue when the window isn’t active. Our QA team hasn’t run a complete test against the UI so I can’t say if there is any situations where it doesn’t work, but it seems to be the best solution that I’ve come up with to date.
I’m open to any other suggestions if anyone out there has a better idea of what could be causing the button to not update.