【问题标题】:What if CanExecute has to be a method, and not a property?如果 CanExecute 必须是方法而不是属性怎么办?
【发布时间】:2017-03-20 09:51:50
【问题描述】:

所以我有这个观点:

<StackPanel>
        <TextBox x:Name="Name"/>
        <Button x:Name="SayHello"
                Content="Click Me" />
    </StackPanel>

我有这个 ViewModel:

internal class ShellViewModel : PropertyChangedBase
    {

        private string name;

        public string Name
        {
            get { return name; }
            set
            {
                name = value;
                NotifyOfPropertyChange(() => Name);
                NotifyOfPropertyChange(() => CanSayHello());
            }
        }

        public bool CanSayHello()
        {
            bool isenabled = !string.IsNullOrWhiteSpace(Name);
            return isenabled;
        }

        public void SayHello()
        {
            MessageBox.Show(string.Format("Hello, {0}!", Name));
        }
    }

但是每当我在文本框中输入一些值时,我都会得到这个异常:

{“无法将'System.Linq.Expressions.InstanceMethodCallExpressionN'类型的对象转换为'System.Linq.Expressions.MemberExpression'类型。”}

在我正在开发的商业应用程序中,我必须将 VM 中的 CanSayHello() 成员作为方法,而不是作为属性。我该怎么办?

【问题讨论】:

  • 我在这里使用 Caliburn.Micro。
  • NotifyOfPropertyChange 作为名称直接表示它通知属性更改。如果您仅限于使用CanSayHello() 作为操作守卫,那么您无能为力。
  • private getter bool,否则你将不得不滚动你自己的命令......或者使用绑定。考虑到它被封装在单个对象中并且没有向量可以利用......这种设计要求很愚蠢。

标签: wpf mvvm caliburn.micro inotifypropertychanged


【解决方案1】:

您有这个例外,因为您在 CanSayHello 上调用 NotifyOfPropertyChange,而 CanSayHello 是一种方法,而不是属性。

改为:

public bool CanSayHello
{
     get { return !string.IsNullOrWhiteSpace(Name); }
}

【讨论】:

  • “在我正在开发的商业应用程序中,我必须将 VM 中的 CanSayHello() 成员作为方法,而不是作为属性。”
  • 我不相信你可以随心所欲,例如作为一种方法使用。将其映射到每次更改 Name 属性时调用 NotifyOfPropertyChange 的属性,Caliburn 将根据 CanSayHello 布尔结果评估是否可以启用或禁用 SayHello 按钮。由于 SayHello 是一个没有任何参数的按钮,因此 Caliburn.Micro 无法知道何时调用 CanSayHello 方法。为什么不能将其作为财产?
【解决方案2】:

您应该使用命令将操作绑定到 UI 项。 ICommand 的实现称为 RelayCommand,通常用于大多数 WPF 项目。它允许您使用方法、属性或谓词。

public class RelayCommand : ICommand
{
    readonly Action<object> _execute;
    readonly Predicate<object> _canExecute;

    public RelayCommand(Action<object> execute)
        : this(execute, null)
    {
    }

    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException(nameof(execute));

        _execute = execute;
        _canExecute = canExecute;
    }

    [DebuggerStepThrough]
    public bool CanExecute(object parameter)
    {
        return _canExecute == null ? true : _canExecute(parameter);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }
}

【讨论】:

  • Caliburn 有自己的命令实现,以保存代码样板,称为操作,应改为使用。 OP的问题用它来绑定函数和按钮的点击事件。
  • 虽然它对 MVVM 的立场是有建设性的,但却错过了关于 Caliburn.Micro 框架的 OP 问题的全部要点。
猜你喜欢
  • 2014-04-02
  • 1970-01-01
  • 2020-08-05
  • 1970-01-01
  • 1970-01-01
  • 2016-06-22
  • 2011-07-23
  • 2017-05-13
  • 1970-01-01
相关资源
最近更新 更多