How to make Databinding type safe and support refa

2019-01-02 19:40发布

When I wish to bind a control to a property of my object, I have to provide the name of the property as a string. This is not very good because:

  1. If the property is removed or renamed, I don’t get a compiler warning.
  2. If a rename the property with a refactoring tool, it is likely the data binding will not be updated.
  3. I don’t get an error until runtime if the type of the property is wrong, e.g. binding an integer to a date chooser.

Is there a design-pattern that gets round this, but still has the ease of use of data-binding?

(This is a problem in WinForm, Asp.net and WPF and most likely lots of other systems)

I have now found "workarounds for nameof() operator in C#: typesafe databinding" that also has a good starting point for a solution.

If you are willing to use a post processor after compiling your code, notifypropertyweaver is well worth looking at.


Anyone knows of a good solution for WPF when the bindings are done in XML rather then C#?

7条回答
笑指拈花
2楼-- · 2019-01-02 20:11

The nameof operator was implemented in C# 6.0 with .NET 4.6 and VS2015 in July 2015. The following is still valid for C# < 6.0

To avoid strings which contain property names, I've written a simple class using expression trees to return the name of the member:

using System;
using System.Linq.Expressions;
using System.Reflection;

public static class Member
{
    private static string GetMemberName(Expression expression)
    {
        switch (expression.NodeType)
        {
            case ExpressionType.MemberAccess:
                var memberExpression = (MemberExpression) expression;
                var supername = GetMemberName(memberExpression.Expression);

                if (String.IsNullOrEmpty(supername))
                    return memberExpression.Member.Name;

                return String.Concat(supername, '.', memberExpression.Member.Name);

            case ExpressionType.Call:
                var callExpression = (MethodCallExpression) expression;
                return callExpression.Method.Name;

            case ExpressionType.Convert:
                var unaryExpression = (UnaryExpression) expression;
                return GetMemberName(unaryExpression.Operand);

            case ExpressionType.Parameter:
                return String.Empty;

            default:
                throw new ArgumentException("The expression is not a member access or method call expression");
        }
    }

    public static string Name<T>(Expression<Func<T, object>> expression)
    {
        return GetMemberName(expression.Body);
    }

    public static string Name<T>(Expression<Action<T>> expression)
    {
        return GetMemberName(expression.Body);
    }
}

You can use this class as follows. Even though you can use it only in code (so not in XAML), it is quite helpful (at least for me), but your code is still not typesafe. You could extend the method Name with a second type argument which defines the return value of the function, which would constrain the type of the property.

var name = Member.Name<MyClass>(x => x.MyProperty); // name == "MyProperty"

Until now I haven't found anything which solves the databinding typesafety issue.

Best Regards

查看更多
登录 后发表回答