为什么RelayCommands通常使用延迟初始化?

20

当使用Josh Smith的RelayCommand时,我看到的大多数示例都使用惰性初始化,例如:

public class ViewModel
{
    private ICommand myCommand;

    public ICommand MyCommand
    {
        get
        {
            if (myCommand == null)
            {
                myCommand = new RelayCommand(p => DoSomething() );
            }

            return myCommand;
        }
    }
    // ... stuff ...

}

不要像这样在构造函数中创建RelayCommand:

public class ViewModel
{
    public ViewModel()
    {
            MyCommand = new RelayCommand(p => DoSomething());
    }

    public ICommand MyCommand
    {
        get;
        private set;

    }

    // ... stuff ...
}

在这里使用惰性初始化有什么好处?在设置绑定时它将不得不调用get属性,所以我看不出使用这种方法的理由,与在构造函数中设置一切相比。

我有什么地方没理解到吗?


你是对的。延迟初始化RoutedCommands没有任何意义,因为它们非常轻量级,并且一旦视图绑定到它们,它们就会被加载。 - jbe
1个回答

15

实际上,在WPF和Silverlight中,RelayCommand只会在每个绑定时获取一次,因此您根本不需要存储后备字段:

public ICommand MyCommand
{
    get
    {
        return new RelayCommand(p => DoSomething());
    }
}

因此,虽然按照您的建议在构造函数中创建它没有任何问题,但几乎没有理由这样做。


3
"WPF和Silverlight每次绑定只会获取一次中继命令"——我知道在实践中是这样的。但是,考虑到文档并没有承诺这种行为,每次检索属性值时创建一个新对象真的明智吗?假设有一天微软出于某种原因决定让您的模型对象保留命令对象引用而不是将其缓存到其他地方,并且他们每次需要时都从属性获取值,那会发生什么? - Peter Duniho
4
不仅是微软这样,我的视图模型也经常直接从自己的方法中调用其命令(和CanExecute())。因此,每次创建新实例都是不明智的。 - BoltClock
@BoltClock:很好的观点。我将更明确地说明另一篇帖子中的场景。 - Peter Duniho
无论如何,为了主要观点,还是要点赞答案——绑定会立即发生,仅一次(每个视图+视图模型),从而避免了懒惰初始化的需要。如果您使用的C#版本不支持它(这是一个较旧的问答),您仍应该使用后备字段;在C# 6及更高版本中,只读属性可以自动实现。 - BoltClock
2
@Peter Duniho:我意识到为什么我没有利用字段/属性初始化程序,因为我的命令本身也调用视图模型实例方法。尽管我可以将这些初始化移动到构造函数中,但我不确定它会有多大的区别。我选择不进行任何重构。 - BoltClock
2
那是一个可怕的解决方案。你的视图可以多次绑定到相同的命令(可能是主菜单中的一个按钮和上下文菜单中的另一个按钮)。如果为同一命令创建多个实例,则可能更难进行调试。 - Alois

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接