如何使WPF数据绑定具有重构安全性?

7

我正在进行我的第一个WPF项目,到目前为止,我很喜欢它。学习曲线比我预期的要高,但是WPF还是相当不错的。然而,我在数据绑定概念方面有些困惑。我有一个具体的问题,就是如何使我的数据绑定声明重构安全?考虑以下示例。

public class MyDataObject
{
  public string FooProperty { get; set; }
}

void Bind() 
{
  var gridView = myListView.View as GridView;
  gridView.Columns.Clear();
  gridView.Columns.Add(
    new GridViewColumn() 
      { 
        Header = "FooHeader", 
        DisplayMember = new Binding("FooProperty")
      }
    );
  List<MyDataObject> source = GetData();
  myListView.ItemsSource = source;
}

那如果我将数据对象中的FooProperty重命名为其他名称呢?数据绑定将会失效,但是由于绑定仅以文本方式声明,因此不会出现编译错误。有没有一种方法可以使绑定更加易于重构呢?

3个回答

3
您可以使用Lambda表达式来表示属性名称,而不是直接使用名称:
    protected static string GetPropertyName<TSource, TResult>(Expression<Func<TSource, TResult>> expression)
    {
        if (expression.NodeType == ExpressionType.Lambda && expression.Body.NodeType == ExpressionType.MemberAccess)
        {
            PropertyInfo prop = (expression.Body as MemberExpression).Member as PropertyInfo;
            if (prop != null)
            {
                return prop.Name;
            }
        }
        throw new ArgumentException("expression", "Not a property expression");
    }

您可以像这样使用它:
...
DisplayMember = new Binding(GetPropertyName((MyDataObject o) => o.FooProperty))
...

好的,这有点啰嗦...如果你想要更简洁的内容,你也可以创建一个帮助方法:

public Binding CreateBinding<TSource, TResult>(Expression<Func<TSource, TResult>> expression)
{
    return new Binding(GetPropertyName(expression))
}

...
DisplayMember = CreateBinding((MyDataObject o) => o.FooProperty)
...

那样的话,如果你重命名属性,重构应该可以正常工作(当然,XAML除外...)。

非常聪明。是的,XAML仍然是一个问题,但至少在我目前的情况下,我必须动态构建列,所以这不是目前的问题。谢谢! - Brian Gideon

2
重构依赖于工具支持,识别代码中的特定符号(C#,XAML,config等)表示正在重命名的标识符。
在您提供的示例中,字符串文字“FooProperty”不能被100%解释为属于MyDataObject,除非对GridView的内部工作原理以及WPF和其他框架中所有其他类型有特殊了解。
但是,在DataTemplate中,可以有99%的把握:
<DataTemplate DataType="{x:Type local:MyDataObject}">
    <TextBlock Text="{Binding Path=FooProperty}" />
</DataTemplate>

我使用(并且很信赖)一个名为ReSharper(也称为R#)的IDE插件,它非常智能化地处理这些事情。如果你重命名了FooProperty,R#会自动帮你重命名该属性。
在你的例子中,如果你要重命名该属性,R#仍然会有用处。它会查找所有字面字符串(在你的情况下)和注释中的实例(如果你已经对某些代码进行了注释,并可能稍后取消注释,这将非常有用)。你会得到一个树形视图,显示每个字面值的上下文,并且在继续之前可以选中/取消选中单个用法/文件/文件夹/项目。
如果你的预算允许,购买R#。如果你的预算不允许,下载一个试用版,到最后你的预算也会有余地。确保打印出快捷键以提高学习体验。

0

您可以使用反射来确定属性名称。当然,如果每个类有多个绑定,这可能会导致问题,因此或许还需要使用自定义特性(这些特性也可以通过反射获得)来获取有关命名属性应该绑定到的正确绑定字段的 '提示'。

但是这可能只是将不可重构的魔术字符串转移到应用程序的其他部分,我不能说我尝试过并且成功了。


重构是设计时发生的事情,而反射是运行时发生的。 (实际上,在“io”语言中,重构可以在运行时发生,但那是另一回事!) - Drew Noakes
当然,但是我理解问题的时候,重构不会捕捉到绑定中的“魔术字符串”FooProperty,因此属性会更改而绑定不会;通过反射在运行时获取正确的字符串,您始终在查看最新的世界,并且不依赖于确保更改了所有常量。 - Mikeb
@Mikeb - 这取决于您使用的重构工具。 - Drew Noakes

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