Disable WPF buttons during longer running process, the MVVM way
Ok the CanExecute
method will not work because the click will immediately put you into your long-running task.
So here's how I would do it:
Make your view model implement INotifyPropertyChanged
Add a property called something like:
public bool IsBusy { get { return this.isBusy; } set { this.isBusy = value; RaisePropertyChanged("IsBusy"); } }
Bind your buttons to this property in this manner:
<Button IsEnabled="{Binding IsBusy}" .. />
In your ShowMessage/CallExternal device methods add the line
IsBusy = true;
Should do the trick
I think this is a bit more elegant:
XAML:
<Button IsEnabled="{Binding IsGuiEnabled}" Content="Simulate external device" Command="{Binding DeviceCommand}" Height="50" Margin="0 10"></Button>
C# (using async & await):
public class MainWindowViewModel : INotifyPropertyChanged
{
private bool isGuiEnabled;
/// <summary>
/// True to enable buttons, false to disable buttons.
/// </summary>
public bool IsGuiEnabled
{
get
{
return isGuiEnabled;
}
set
{
isGuiEnabled = value;
OnPropertyChanged("IsGuiEnabled");
}
}
public ICommand DeviceCommand
{
get
{
return new RelayCommand(this.CallExternalDevice, this.IsGuiEnabled);
}
}
private async void CallExternalDevice(object obj)
{
IsGuiEnabled = false;
try
{
await Task.Factory.StartNew(() => Thread.Sleep(3000));
}
finally
{
IsGuiEnabled = true;
}
}
}
Try this:
//Declare a new BackgroundWorker
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (o, ea) =>
{
try
{
// Call your device
// If ou need to interact with the main thread
Application.Current.Dispatcher.Invoke(new Action(() => //your action));
}
catch (Exception exp)
{
}
};
//This event is raise on DoWork complete
worker.RunWorkerCompleted += (o, ea) =>
{
//Work to do after the long process
disableGui = false;
};
disableGui = true;
//Launch you worker
worker.RunWorkerAsync();