【问题标题】:Is there a way of making C# binding work statically?有没有办法让 C# 绑定静态工作?
【发布时间】:2010-11-30 19:06:42
【问题描述】:

这可能适用于其他地方,但是在 WinForms 中,当我使用绑定时,我发现很多方法都想采用要绑定到的属性的名称。比如:

class Person
{
    public String Name { get { ... } set { ... } }
    public int Age { get { ... } set { ... } }
}

class PersonView
{
    void Bind(Person p)
    {
        nameControl.Bind(p,"Name");
        ageControl.Bind(p,"Age");
    }
}

我一直遇到的最大问题是“姓名”和“年龄”被指定为字符串。这意味着如果有人重命名 Person 的属性之一,编译器将无济于事。代码可以正常编译,但绑定会被破坏。

有没有解决我错过的标准方法?感觉就像我需要一些关键字,也许称为 stringof 来匹配现有的 typeof。你可以像这样使用它:

ageControl.Bind(p,stringof(p.Age).Name);

stringof 可以返回一些类,该类具有获取完整路径、部分路径或字符串的属性,因此您可以自己解析它。

这样的事情已经可行了吗?

【问题讨论】:

  • 这不是动态绑定那么多的C#,这是WinForms。
  • 是的。即使您不使用 WinForms,这种语言功能也可能会派上用场。

标签: c# language-features


【解决方案1】:

看看这个code snippet我已经在另一个问题中发布了,它可以帮助你! (但仅限于使用 .NET 3.5 时)

最好的问候
奥利弗·哈纳皮

【讨论】:

    【解决方案2】:

    您可以使用表达式树来做到这一点,正如 in this question 所解释的那样

    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");
    }
    
    ...
    
    ageControl.Bind(p, GetPropertyName((Person p) => p.Age));
    

    【讨论】:

      【解决方案3】:

      您可以使用表达式来获取经过编译器检查的绑定。 例如,在当前的一个项目中,我们设置了这样的绑定:

      DataBinder
          .BindToObject(this)
          .ObjectProperty(c => c.IsReadOnly)
              .Control(nameTextBox, n => n.ReadOnly)
              .Control(addressControl, n => n.ReadOnly)
      

      支持这种风格的代码分为几个类:

      public static class DataBinder
      {
          public static DataBinderBindingSourceContext<TDataSource> BindToObject<TDataSource>(TDataSource dataSource)
          {
              return new DataBinderBindingSourceContext<TDataSource>(dataSource);
          }
      }
      
      public class DataBinderBindingSourceContext<TDataSource> 
      {
          public readonly object DataSource;
      
          public DataBinderBindingSourceContext(object dataSource)
          {
              DataSource = dataSource;
          }
      
          public DataBinderControlContext<TDataSource, TProperty> ObjectProperty<TProperty>(Expression<Func<TDataSource, TProperty>> property)
          {
              return new DataBinderControlContext<TDataSource, TProperty>(this, property);
          }
      }
      
      public class DataBinderControlContext<TDataSource, TProperty>
      {
          readonly DataBinderBindingSourceContext<TDataSource> BindingSourceContext;
          readonly string ObjectProperty;
      
          public DataBinderControlContext
              (
                  DataBinderBindingSourceContext<TDataSource> bindingSourceContext,
                  Expression<Func<TDataSource, TProperty>> objectProperty
              )
          {
              BindingSourceContext = RequireArg.NotNull(bindingSourceContext);
              ObjectProperty = ExpressionHelper.GetPropertyName(objectProperty);
          }
      
          public DataBinderControlContext<TDataSource, TProperty> Control<TControl>(TControl control, Expression<Func<TControl, TProperty>> property)
              where TControl : Control
          {
              var controlPropertyName = ExpressionHelper.GetPropertyName(property);
              control.DataBindings.Add(controlPropertyName, BindingSourceContext.DataSource, ObjectProperty, true);
      
              return this;
          }
      }
      
      public static class ExpressionHelper
      {
          public static string GetPropertyName<TResult>(Expression<Func<TResult>> property)
          {
              return GetMemberNames(((LambdaExpression)property).Body).Skip(1).Join(".");
          }
      
          public static string GetPropertyName<T, TResult>(Expression<Func<T, TResult>> property)
          {
              return GetMemberNames(((LambdaExpression)property).Body).Join(".");
          }
      
          static IEnumerable<string> GetMemberNames(Expression expression)
          {
              if (expression is ConstantExpression || expression is ParameterExpression)
                  yield break;
      
              var memberExpression = (MemberExpression)expression;
      
              foreach (var memberName in GetMemberNames(memberExpression.Expression))
                  yield return memberName;
      
              yield return memberExpression.Member.Name;
          }
      }
      
      public static class StringExtentions
      {
          public static string Join(this IEnumerable<string> values, string separator)
          {
              if (values == null)
                  return null;
      
              return string.Join(separator, values.ToArray());
          }
      }
      

      【讨论】:

        【解决方案4】:

        您可以使用反射来查找名称 ;-)

        这当然是一个循环引用,你会使用你认为的名字来找到相同的名字(或者什么都找不到,这意味着属性被重命名了......但是有一个想法(或者更确切地说,一个技巧):通过对您希望使用的属性进行无操作引用,您将获得编译时确认它仍然存在。唯一的问题是如果有人只是交换各种属性名称;在这种情况下,名称仍然存在(没有编译时错误),但具有不同的应用程序级语义(应用程序输出中可能出现意外)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-03-22
          • 1970-01-01
          • 2016-04-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-10-15
          • 1970-01-01
          相关资源
          最近更新 更多