私はWPF/MVVMアプリを持っています。これは、いくつかのボタンを備えた1つのウィンドウで構成されています。
各ボタンは、外部デバイス(USBミサイルランチャー)への呼び出しをトリガーします。これには数秒かかります。
デバイスの実行中、GUIはフリーズします。
(アプリの唯一の目的はUSBデバイスを呼び出すことであり、デバイスが移動している間は他に何もできないため、これは問題ありません!)
少し醜いのは、デバイスが移動している間、フリーズされたGUIが追加のクリックを受け入れることだけです。
それでもデバイスが動き、同じボタンをもう一度クリックすると、最初の「実行」が終了するとすぐにデバイスが再び動き始めます。
そのため、1つのボタンがクリックされるとすぐに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
Josh Smithの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で同様の問題に対するいくつかの答えでそれを見つけました)
助言がありますか?