【发布时间】:2013-01-03 17:09:28
【问题描述】:
我有一个 WPF/MVVM 应用程序,它由一个窗口和几个按钮组成。
每个按钮都会触发对外部设备(USB missile launcher)的调用,这需要几秒钟。
设备运行时,GUI 被冻结。
(没关系,因为应用程序的唯一目的是调用 USB 设备,而您可以'在设备移动时无论如何都不要做任何其他事情!)
唯一有点难看的是,冻结的 GUI 在设备移动时仍然接受额外的点击。
当设备仍然移动并且我再次单击同一个按钮时,设备会在第一次“运行”完成后立即再次开始移动。
所以我想在单击一个按钮后立即禁用 GUI 中的所有按钮,并在按钮的命令完成运行后再次启用它们。
我找到了一个看起来符合 MVVM 的解决方案。
(至少对我来说......请注意,我仍然是 WPF/MVVM 初学者!)
问题是,当我调用与 USB 设备通信的外部库时,此解决方案不起作用(例如:按钮未禁用)。
但禁用 GUI 的实际代码是正确的,因为当我将外部库调用替换为 MessageBox.Show() 时,它确实工作。
我构建了一个重现问题的最小工作示例 (complete demo project here):
这是视图:
<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 from Josh Smith's MSDN article):
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 上对类似问题的几个答案中发现了这一点)
有什么建议吗?
【问题讨论】:
标签: c# wpf data-binding mvvm