У меня есть приложение WPF/MVVM, состоящее из одного окна с несколькими кнопками.
Каждая из кнопок вызывает вызов внешнего устройства (USB-ракета-носитель), который занимает несколько секунд.
Пока устройство работает, графический интерфейс заморожен.
( Это нормально, потому что единственная цель приложения - вызвать USB-устройство, и вы все равно ничего не сделаете, пока устройство движется!)
Единственное, что немного уродливо, заключается в том, что замороженный GUI по-прежнему принимает дополнительные клики во время движения устройства.
Когда устройство все еще перемещается и я нажимаю на ту же кнопку во второй раз, устройство сразу же начинает движение снова, как только закончится первый "запуск".
Поэтому я хотел бы отключить все кнопки в графическом интерфейсе сразу после нажатия одной кнопки и включить их снова, когда команда кнопки завершит работу.
Я нашел решение для этого, которое выглядит MVVM-совместимым.
(по крайней мере, для меня... заметьте, что я все еще начинающий WPF/MVVM!)
Проблема в том, что это решение не работает (как в случае: кнопки не отключены), когда я вызываю внешнюю библиотеку, которая взаимодействует с USB-устройством.
Но фактический код для отключения GUI правильный, потому что он работает, когда я заменяю внешний вызов библиотеки на MessageBox.Show()
.
Я построил минимальный рабочий пример, который воспроизводит проблему (полный демонстрационный проект здесь):
Это представление:
<Window x:Class="WpfDatabindingQuestion.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel>
<Button Content="MessageBox" Command="{Binding MessageCommand}" Height="50"></Button>
<Button Content="Simulate external device" Command="{Binding DeviceCommand}" Height="50" Margin="0 10"></Button>
</StackPanel>
</Grid>
</Window>
... и это ViewModel (используя RelayCommand
из статьи MSDN Джоша Смита):
using System.Threading;
using System.Windows;
using System.Windows.Input;
namespace WpfDatabindingQuestion
{
public class MainWindowViewModel
{
private bool disableGui;
public ICommand MessageCommand
{
get
{
return new RelayCommand(this.ShowMessage, this.IsGuiEnabled);
}
}
public ICommand DeviceCommand
{
get
{
return new RelayCommand(this.CallExternalDevice, this.IsGuiEnabled);
}
}
// here, the buttons are disabled while the MessageBox is open
private void ShowMessage(object obj)
{
this.disableGui = true;
MessageBox.Show("test");
this.disableGui = false;
}
// here, the buttons are NOT disabled while the app pauses
private void CallExternalDevice(object obj)
{
this.disableGui = true;
// simulate call to external device (USB missile launcher),
// which takes a few seconds and pauses the app
Thread.Sleep(3000);
this.disableGui = false;
}
private bool IsGuiEnabled(object obj)
{
return !this.disableGui;
}
}
}
Я подозреваю, что открытие MessageBox
вызывает некоторые вещи в фоновом режиме, которые делают не, когда я просто вызываю внешнюю библиотеку.
Но я не могу найти решение.
Я также пробовал:
- реализация
INotifyPropertyChanged
(и созданиеthis.disableGui
свойства и вызовOnPropertyChanged
при его изменении) - вызов
CommandManager.InvalidateRequerySuggested()
повсюду
(Я обнаружил, что в нескольких ответах на подобные проблемы здесь на SO)
Любые предложения?