使用属性定义UI的属性

本文关键字:属性 UI 定义 | 更新日期: 2023-09-27 18:22:06

对于一个新项目,我最近被要求研究一种将与UI呈现相关的信息附加到WPF应用程序中的业务对象的方法。例如,报表类:

class ExecutionReport
{
    [Displayable(Bold, Background=Color.Red)]
    public String OrderId{get; private set;}
    [Displayable(Normal, HAlignment=Center)]
    public String Symbol {get; private set;}
    // this should be hidden as it doesn't have DisplayableAttribute
    public String ClientOrderId {get; private set;}]
    [Displayable(Normal, HAlignment=Right, 
        Format("If [Position] < 0 then Background=Color.Red"), 
        Format("If [Position] > 0 then Background=Color.Lime"),
        DisplayFormat("+#;-#;0")]
    public Int Position {get; private set;}
}

这对我来说是一种非常新的方法,因为在我开发的大多数wpf-MVVM应用程序中,视图和视图模型都有明确的分离,我尽可能地将UI特定的细节排除在VM之外。相反,我倾向于使用资源字典和应用于视图层绑定的简单转换器来编写这篇文章。

我的问题是:有没有任何wpf/mvvm框架使用这种实现?如果是这样的话,我很想知道它将如何实现。

有什么明显的陷阱吗?我首先想到的是

  • 更改通知(即INotifyPropertyChanged以触发视图的更新)。现在实施起来会不会困难得多?

  • 难以利用资源字典获取系统范围的值。例如,也许我想更改整个应用程序中使用的红色。我必须ctrl+f遍历并找到业务对象中使用它的每个位置,并对其进行更改,而不是修改单个StaticResource

  • 无法利用DesignTime DataContexts

  • 性能。这似乎需要大量使用反射,而反射的性能可能不如典型的值转换器

我很有兴趣看看我在第二点和第三点上是否正确,或者这两件事是否仍然可以实现?

最终,我觉得这是一个糟糕的设计,我倾向于编写一个不同的实现,向感兴趣的一方展示我通常会如何处理这类问题。我只是想确保我不会错过一些明显的东西,这些东西可能会让这件衣服更优雅。

使用属性定义UI的属性

IMO这似乎是一个可怕的想法,它们似乎都是应该作为XAML转换器实现的示例。

所有的要点列表似乎都是避免这样做的正当理由。

注意:框架中有一组属性已经提供了一些UI功能(非常有限),请参阅System.ComponentModel.DataAnnotations命名空间。

这种方法非常流行,它被称为面向方面编程(ASP.NET MVC充分利用了它)。写得这么快的最受欢迎的库是PostSharp(请参阅客户案例研究,有些公司已经将其用于WPF)。PostSharp中最好的东西是使用编译时编织

对于第一点:PostSharp在NotifyPropertyChanged方面得到了很好的测试,您可以将[NotifyPropertyChanged]属性添加到类中,当值更改时,所有属性都将调用PropertyChanged

第二点:您可以随时让您的属性查找StaticResources,并在属性中传递资源键。

对于第三点(尽管我不能100%确定)和第四点:编译时编织意味着方面在编译时被"附加"到代码中——就像您将它写在附加了属性的方法/属性中一样。它就像后编译编译器,不使用反射(如果您编写的方面不使用反射),所以性能非常好。

然而,在你给出的例子中,我宁愿使用值转换器和@AwkwardCoder所说的样式,但方面(属性)对"视图"也很有用:它们非常适合验证。

我同意这似乎是一个可怕的想法,你的评论。。。

在我工作过的大多数wpf MVVM应用程序中视图和视图模型的分离,我尽可能地努力以将特定于UI的详细信息排除在VM之外。相反,我会靠着使用资源字典和简单转换器编写应用于视图层中的绑定

我认为总结了为什么以及如何避免它。

将业务对象直接与实现细节(如颜色、水平对齐或位置)联系起来,似乎是短期的胜利(但却是长期的地狱)。