如何使数据绑定类型安全和支持重构绑定、重构、类型、安全

2023-09-02 10:17:11 作者:早已放下

当我想一个控件绑定到我的对象的属性,我必须提供财产作为字符串的名称。这不太好,因为:

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:

如果该属性已被删除或 改名,我没有得到一个编译器 警告。 如果一个重命名属性 与重构工具,它是 有可能的数据绑定不会 更新。 在我没有得到一个错误,直到 如果运行属性的类型 是错误的,例如结合的整数 日期选择。 If the property is removed or renamed, I don’t get a compiler warning. If a rename the property with a refactoring tool, it is likely the data binding will not be updated. 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?

(这是在winform,Asp.net和WPF和最有可能的许多其它系统的问题)

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

我现在已经找到了workarounds对于nameof()运算符在C#中:类型安全的数据绑定这也有一个很好的出发点,解决

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

如果你愿意编译code后使用后处理器, notifypropertyweaver 是非常值得期待的。

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

任何人都知道的WPF一个很好的解决方案时,绑定完成后的XML而不是C#?

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

推荐答案

感谢奥利弗是他们让我开始了我现在有一个解决方案,既支持重构,是类型安全的。这也让我实现INotifyPropertyChanged所以它被更名的属性科佩斯。

Thanks to Oliver for getting me started I now have a solution that both supports refactoring and is type safe. It also let me implement INotifyPropertyChanged so it copes with properties being renamed.

它的用法是这样的:

checkBoxCanEdit.Bind(c => c.Checked, person, p => p.UserCanEdit);
textBoxName.BindEnabled(person, p => p.UserCanEdit);
checkBoxEmployed.BindEnabled(person, p => p.UserCanEdit);
trackBarAge.BindEnabled(person, p => p.UserCanEdit);

textBoxName.Bind(c => c.Text, person, d => d.Name);
checkBoxEmployed.Bind(c => c.Checked, person, d => d.Employed);
trackBarAge.Bind(c => c.Value, person, d => d.Age);

labelName.BindLabelText(person, p => p.Name);
labelEmployed.BindLabelText(person, p => p.Employed);
labelAge.BindLabelText(person, p => p.Age);

Person类展示了如何实现INotifyPropertyChanged的一个类型安全的方式(或see这个答案实施INotifyPropertyChanged的的其他相当不错的方式, ActiveSharp - 自动INotifyPropertyChanged的看起来也不错):

The person class shows how to implemented INotifyPropertyChanged in a type safe way (or see this answer for a other rather nice way of implementing INotifyPropertyChanged, ActiveSharp - Automatic INotifyPropertyChanged also looks good ):

public class Person : INotifyPropertyChanged
{
   private bool _employed;
   public bool Employed
   {
      get { return _employed; }
      set
      {
         _employed = value;
         OnPropertyChanged(() => c.Employed);
      }
   }

   // etc

   private void OnPropertyChanged(Expression<Func<object>> property)
   {
      if (PropertyChanged != null)
      {
         PropertyChanged(this, 
             new PropertyChangedEventArgs(BindingHelper.Name(property)));
      }
   }

   public event PropertyChangedEventHandler PropertyChanged;
}

本的WinForms约束力的辅助类有肉在里面,它使所有的工作:

The WinForms binding helper class has the meat in it that makes it all work:

namespace TypeSafeBinding
{
    public static class BindingHelper
    {
        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:
                case ExpressionType.Constant: //Change
                    return String.Empty;
                default:
                    throw new ArgumentException("The expression is not a member access or method call expression");
            }
        }

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

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

        public static void Bind<TC, TD, TP>(this TC control, Expression<Func<TC, TP>> controlProperty, TD dataSource, Expression<Func<TD, TP>> dataMember) where TC : Control
        {
            control.DataBindings.Add(Name(controlProperty), dataSource, Name(dataMember));
        }

        public static void BindLabelText<T>(this Label control, T dataObject, Expression<Func<T, object>> dataMember)
        {
            // as this is way one any type of property is ok
            control.DataBindings.Add("Text", dataObject, Name(dataMember));
        }

        public static void BindEnabled<T>(this Control control, T dataObject, Expression<Func<T, bool>> dataMember)
        {       
           control.Bind(c => c.Enabled, dataObject, dataMember);
        }
    }
}

这是利用了很多新的东西在C#3.5和只显示什么是可能的。现在,只要我们有卫生宏的口齿不清的程序员可能会停止给我们打电话二等公民)

This makes use of a lot of the new stuff in C# 3.5 and shows just what is possible. Now if only we had hygienic macros lisp programmer may stop calling us second class citizens)

 
精彩推荐