我执行调用LogInRequest()
的{{1}}。该视图有一个名为LogInView.ShowDialog()
的命令。执行Command时,它以VerifyLogInCommand
完成,似乎关闭了Dialog。但是,在关闭对话框(不间断)后,该视图的命令的CanExecute方法this.CloseAction()
中的断点仍然被击中。我在调用ShowDialog后尝试将视图设置为null但没有更改。
为什么在窗口关闭/ null时仍然会评估Command / CanExecute?
LogInView.xaml.cs
VerifyLogInCanExecute
LogInViewModel.cs
public LogInOutView()
{
InitializeComponent();
// Data context
IModule existingVM = SessionViewModel.Instance.ModulesOpen.Single(mod => mod.ModuleName == "LogIn");
LogInViewModel livm = (LogInViewModel)existingVM;
this.DataContext = livm;
// Cancel Handler
livm.CloseAction = new Action(() => this.Close());
}
答案 0 :(得分:4)
如果您使用的是MvvmLight中的RelayCommand
,则会通过将订阅转发到CanExecuteChanged
来实现其CommandManager.RequerySuggested
事件。这有效地允许RelayCommand
以RoutedCommand
在WPF中的方式更新自己的状态; RequerySuggested
事件在某些条件下触发,包括每次焦点更改或窗口被激活(de)时。 RequerySuggested
事件使用弱事件处理程序来缓解泄露的订阅,但WPF使用的弱事件实现并不是非常努力清理自己,因此订阅可能仍然保持活跃一段时间(甚至可能无限期)。
您的CanExecute
回调会出现以便不间断地重新评估,因为每次遇到断点时,Visual Studio都会从您的应用程序中窃取焦点,当您点击“恢复”时# 39;,您的应用程序被重新激活,从而触发RequerySuggested
事件并导致CanExecute
被重新评估。反过来,这会再次触发断点 ,并且您会在一个循环中被捕获,直到您禁用断点。
如果您的视图模型知道其已关闭状态,我会将您的VerifyLogInCanExecute
属性更改为:
public bool VerifyLogInCanExecute
{
get { return !IsClosed && CheckRequiredPasswordLength(Password); }
}
至少那时你不会做更多的工作。另一种选择是在关闭视图模型时将登录命令设置为null
(或空/无操作命令)(并引发相应的PropertyChanged
事件)。这将导致绑定到命令的任何按钮取消订阅其CanExecuteChanged
事件。
答案 1 :(得分:1)
Mike Storbl指出Mvvm light的RelayCommand使用
CommandManager.RequerySuggested
这是非常广泛的性能,并且由于它引发了
,因此很容易出现分配错误 CanExecuteChangedEvent
每次VisualTree聚焦时。
你应该实现自己的:
public class RelayCommand : ICommand
{
private Func<bool> _canExecute;
private Action _execute;
public RelayCommand(Action execute , Func<bool> canExecute = null)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute();
}
public event EventHandler CanExecuteChanged;
public void RaiseCanExecuteChanged()
{
var temp = Volatile.Read(ref CanExecuteChanged);
if (temp != null)
temp(this, new EventArgs());
}
public void Execute(object parameter)
{
_execute();
}
}
并在需要时从代码中提升它,例如当密码被更改时。
verifyLogInCommand.RaiseCanExecuteChanged();