1

最近的相关问题

我执行LogInRequest()which calls LogInView.ShowDialog()。该视图有一个名为VerifyLogInCommand. 当命令被执行时,它完成后this.CloseAction()似乎关闭了对话框。但是,在对话框关闭(不间断)后,我在该视图命令的 CanExecute 方法VerifyLogInCanExecute中的断点仍然被命中。在调用 ShowDialog 后,我尝试将视图设置为 null,但没有任何变化。

当窗口关闭/为空时,为什么仍在评估 Command/CanExecute?

LogInView.xaml.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());
}

LogInViewModel.cs

public Action CloseAction { get; set; }

private RelayCommand verifyLogInCommand;
public RelayCommand VerifyLogInCommand
{
  get
  {
    if (verifyLogInCommand == null)
    {
      verifyLogInCommand = new RelayCommand(
        param => VerifyLogInExecute(),
        param => VerifyLogInCanExecute);
    }
    return verifyLogInCommand;
  }
}

public void VerifyLogInExecute()
{
  // Validate Login
  Employee employee = ValidateLogin(Password);

  // Clear password field
  ResetExecute();

  // Return false if invalid login
  if (employee == null)
  {
    Result = LogInOutDialogResults.Cancel;
    ConfirmationView c = new ConfirmationView("Invalid Login!");
    c.ShowDialog();
    return;
  }

  // Set Result to LogIn status
  Result = LogInOutDialogResults.LogIn;

  // Set LastAuthorizedEmployee
  SessionViewModel.Instance.LastAuthorizedEmployee = employee;

  // Close View to go back where it was called
  this.CloseAction();
}

public bool VerifyLogInCanExecute
{
  get
  {
    // Password length restrictions
    if (!CheckRequiredPasswordLength(Password)) { return false; }
    return true;
  }
}

public static LogInOutDialogResults LogInRequest()
{
  // Show Login View
  LogInOutDialogResults LogInOutResult = LogInOutDialogResults.Cancel;
  LogInOutView LogInOutView = new LogInOutView()
  {
    Title = "Log In",
    ShowInTaskbar = false,
    Topmost = true,
    ResizeMode = ResizeMode.NoResize,
    Owner = SessionViewModel.Instance.ProfitPOSView
  };
  LogInOutView.ShowDialog();
  LogInOutResult = ((LogInViewModel)LogInOutView.DataContext).Result;

  // LogIn
  if (LogInOutResult == LogInOutDialogResults.LogIn)
  {
    LogInOutView = null;
    return LogInOutDialogResults.LogIn;
  }
}
4

2 回答 2

4

如果您使用RelayCommand来自 MvvmLight,它会CanExecuteChanged通过将订阅转发到CommandManager.RequerySuggested. 这有效地允许 a像在 WPF 中RelayCommand那样更新自己的状态;RoutedCommandRequerySuggested事件在某些条件下触发,包括每次焦点更改或窗口被(停用)激活时。该RequerySuggested事件使用弱事件处理程序来缓解泄露的订阅,但 WPF 使用的弱事件实现在自身之后的清理方面并不是非常勤奋,因此订阅可能仍会保持活动一段时间(甚至可能无限期地)。

您的CanExecute回调似乎在不停地重新评估,因为每次您遇到断点时,Visual Studio 都会从您的应用程序中窃取焦点,并且当您点击“恢复”时,您的应用程序会重新激活,从而触发RequerySuggested事件并导致CanExecute重新评估。这反过来又会再次触发断点,并且您会陷入一个循环,直到您禁用断点为止。

如果您的视图模型知道其关闭状态,我会将您的VerifyLogInCanExecute属性更改为:

public bool VerifyLogInCanExecute
{
    get { return !IsClosed && CheckRequiredPasswordLength(Password); }
}

至少那时你不会做超出必要的工作。另一种选择是在关闭视图模型(并引发适当的事件)时将登录命令设置为null(或空/无操作命令)。PropertyChanged这将导致绑定到命令的任何按钮取消订阅其CanExecuteChanged事件。

于 2013-10-30T15:52:24.140 回答
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(); 
于 2013-10-30T16:15:57.353 回答