Reputation: 11
I have a problem to refresh my UI in a wpf / mvvm project.
When I log out there is a action on UI to display "waiting" object and then do a long process.
All codes I present are not complete
private void btnPower_Click(object sender, RoutedEventArgs e)
{
// IHM changes
btnRightMenuShow.IsEnabled = false;
btnRightMenuShow.Visibility = Visibility.Hidden;
StationWindowViewModel stnWindowVM = (StationWindowViewModel)DataContext;
stnWindowVM.ProgressMode = LoadingProcessViewModel.ProgressMode.Sending;
// PRocess
if (stnWindowVM.PowerOffCmd.CanExecute(null))
{
stnWindowVM.PowerOffCmd.Execute(null);
}
}
Like this the ihm is like frozen during the process and never refresh() before the application ended.
I first try to use a background worker like
private void btnPower_Click(object sender, RoutedEventArgs e)
{
// IHM changes
btnRightMenuShow.IsEnabled = false;
btnRightMenuShow.Visibility = Visibility.Hidden;
StationWindowViewModel stnWindowVM = (StationWindowViewModel)DataContext;
stnWindowVM.ProgressMode = LoadingProcessViewModel.ProgressMode.Sending;
// PRocess
powerOffWorker.RunWorkerAsync(stnWindowVM);
}
private void powerOffWorker_DoWork(object Sender, System.ComponentModel.DoWorkEventArgs e)
{
if (stnWindowVM.PowerOffCmd.CanExecute(null))
{
stnWindowVM.PowerOffCmd.Execute(null);
}
}
In this case the IHM is refreshed but i have threading errors with some code trying to access object created by parent thread on main process (The calling thread cannot access this object because a different thread owns it)
So i try to use a Dispatcher like
private void btnPower_Click(object sender, RoutedEventArgs e)
{
// IHM changes
btnRightMenuShow.IsEnabled = false;
btnRightMenuShow.Visibility = Visibility.Hidden;
StationWindowViewModel stnWindowVM = (StationWindowViewModel)DataContext;
stnWindowVM.ProgressMode = LoadingProcessViewModel.ProgressMode.Sending;
// PRocess
this.Dispatcher.Invoke(new Action(() =>
{
if (stnWindowVM.PowerOffCmd.CanExecute(null))
{
stnWindowVM.PowerOffCmd.Execute(null);
}
}));
}
I also try dispatcher inside backgrounworker but with those dispatcher i don't have anymore problem with calling thread but the UI is not updating.
EDIT
This is my test for async/await implementation
private void btnPower_Click(object sender, RoutedEventArgs e)
{
// IHM changes
btnRightMenuShow.IsEnabled = false;
btnRightMenuShow.Visibility = Visibility.Hidden;
StationWindowViewModel stnWindowVM = (StationWindowViewModel)DataContext;
stnWindowVM.ProgressMode = LoadingProcessViewModel.ProgressMode.Sending;
// PRocess
PowerOffAsync(stnWindowVM);
}
private async void PowerOffAsync(StationWindowViewModel stnWindowVM)
{
await Task.Run(() =>
{
if (stnWindowVM.PowerOffCmd.CanExecute(null))
{
stnWindowVM.PowerOffCmd.Execute(null);
}
});
}
In the PowerOffCmd process ther is some operation on object like list which gives error with calling thread...
Upvotes: 1
Views: 1996
Reputation: 9977
Your probem is that you try to invoke the dispatcher in the awaiting call instead of calling it where you need to work on UI.
Basically, if you do
await Task.Run(() =>
{
this.Dispatcher.Invoke(new Action(() =>
{
if (stnWindowVM.PowerOffCmd.CanExecute(null))
{
stnWindowVM.PowerOffCmd.Execute(null);
}
}));
});
You're doing it wrong since you're processing your async work on the UI thread the whole time.
One work around you can try is invoke the dispatcher in your PowerOffCmd
where it gives you the error. This way, everything except where you need to work on UI thread (modifying controls for example) will execute on a separate thread which will assure that you're UI stay responsive.
Upvotes: 1