1

我想在不引用 WPF 程序集的情况下实现 WPF 的 MVVM 模式的 ViewModel 部分。有问题的部分是命令路由,它要求 ViewModel 实现类型的属性,ICommand以便命令绑定可以工作。

现在,我可以避免ICommand并简单地将属性声明为object. 一切仍然有效,就是这样。但困扰我的是,我仍然必须声明它们,我真的不想这样做,因为它们感觉就像样板代码

我的 ViewModel 目前看起来像这样:

public class HelloWorldViewModel : ViewModel
{
    [BoundProperty]
    public string Name { get; set; }

    [CommandHandler("SayHello")]
    public bool CanSayHello()
    {
        return Name != "" && Name != null;
    }

    [CommandHandler("SayHello")]
    public void SayHello()
    {
        View.ShowMessage("Hello, {0}!", Name);
    }

    public object SayHello { get; private set; }
}

启用命令处理程序(一个和一个可选)的CommandHandlerAttribute运行时发现,而实际上是将自身注入属性设置器和调用的一个方面。我通过使用编译时 IL weaver来实现这一点。ActionFunc<bool>BoundPropertyAttributeINotifyPropertyChanged

理想情况下,我也想隐含最后一行(SayHello 属性)。如果不是 WPF 的要求,那么将它放在源代码中是没有意义的。

因此,很自然地,我正在考虑使用CommandHandlerAttribute方面将必要的 IL 注入到类中,并从本质上创建属性 post-compile。这是相当困难的,尽管一个好的 IL 编织器(例如PostSharp)可以大大简化它。

在我踏上这段旅程之前,我想听听大家对我的方法的看法。好听吗?有没有更好的办法?你会/怎么做?

4

5 回答 5

3

对我来说,这听起来太聪明了。发生了太多的“魔术”。特别是,我不喜欢您的 CommandHandlerAttribute 的魔术字符串和其他方面。也就是说,如果我要走这条路,我会使用类似于 EventAggregator 的东西,但用于命令。IOW,SayHello 根本不存在于您的 ViewModel 上。任何魔术都会创建与 SayHell() 和 CanSayHello() 的命令绑定,而是将命令定位在全局 CommandAggregator 中。只要我们为此使用魔术字符串,CommandAggregator 中的命令就可以被延迟创建,因此您不需要“样板”编码。剩下的就是创建一些 XAML 魔法(标记扩展)来指定 ICommandSource 上的命令。

<Button Command="{my:AggregateCommand SayHello}"/>
于 2009-03-24T16:33:29.057 回答
2

我建议您看看这是如何实施的,它将有所帮助:

“一种魔法” 毫不费力的 INotifyPropertyChanged

[http://visualstudiogallery.msdn.microsoft.com/d5cd6aa1-57a5-4aaa-a2be-969c6db7f88a][1]

作为将其添加到一个属性的示例:

[Magic] 
public string Name { get { return _name; } set { _name = value; } } 
string _name;

将其添加到所有类属性的另一个示例:

[Magic] 
public class MyViewModel: INotifyPropertyChanged 
{ 
  public string Name { get; set; } 
  public string LastName { get; set; } 
  ..... 
}
于 2013-11-05T12:05:57.143 回答
1

玩了 Prism 一段时间后,但在我看起来像 MVVM 之前,我想出了一个我仍然认为有一定有效性的策略:

我创建了一个基于反射的 ICommand 接口的实现。构造函数接受一个目标对象和一个操作名称。使用反射,代码查找名称为“[operation]”的方法、名称为“Can[operation]”或“[operation]Enabled”的属性或方法以及名称为“Can[operation]Changed”或“[操作]启用更改”。只有第一个是必需的,但反射的方法/属性/事件被连接到 ICommand 接口的一个非常基本的实现。

然后,我创建了 IValueConverter 的实现,它将创建前一个类的实例,将要转换的值作为目标对象传递,转换器的参数是操作名称。

有了上述组件,我就可以将按钮的 Command 属性直接绑定到操作的源(以及指定转换器),并将按钮的 CommandParameter 属性设置为操作的名称。通过这种方式,我获得了声明性命令绑定,而命令源没有任何 WPF 的肉体知识。

于 2009-03-24T16:19:39.950 回答
0

我个人认为这很有趣,但我一般会避免它。

避免样板代码(或感觉像样板代码的代码)会产生后果。这似乎是个好主意,因为您不会不断地重新输入内容,但从长远来看,您会降低它的可读性和可理解性。

就个人而言,我尝试设置好的代码模板来为我插入样板代码,并将其包装在区域中,以便我可以将其隐藏在源代码中。在这种情况下,用样板文件填写文件所需的 30 秒(对我而言)比两年后我试图理解代码时花费的 2 小时更痛苦,或者更糟糕的是,两周后有人else 两年后,当他们试图理解我的代码时......

于 2009-03-24T15:54:06.750 回答
0

我认为最好的方法是代理或装饰器模式。您可以在运行时使用 UI/WPF 成员包装/装饰的低级实体。这是最简单但有效的方法,可以节省您的时间,并且不用担心框架、注入等。

唯一的事情是您必须设计一些小型基础设施来用适当的装饰器包装您的实体。

于 2009-03-30T17:52:11.643 回答