关闭ShowDialog后仍在评估视图上的RelayCommand

时间:2013-10-30 15:24:28

标签: c# wpf

Closest related question

我执行调用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());
}

2 个答案:

答案 0 :(得分:4)

如果您使用的是MvvmLight中的RelayCommand,则会通过将订阅转发到CanExecuteChanged来实现其CommandManager.RequerySuggested事件。这有效地允许RelayCommandRoutedCommand在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();