强类型的Windows窗体数据绑定

stu*_*rtd 8 c# data-binding functional-programming winforms

我正在研究使用扩展方法的强类型Windows窗体数据绑定.我从Xavier那里得到了以下的帮助,如下所示:

using System;
using System.Linq.Expressions;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public static Binding Add<T>
        (this ControlBindingsCollection dataBindings,
            object dataSource,
            Expression<Func<Control, object>> controlExpression,
            Expression<Func<T, object>> objectExpression)
    {
        return Add(dataBindings, dataSource, controlExpression, objectExpression, false);
    }

    public static Binding Add<T>
        (this ControlBindingsCollection dataBindings,
            object dataSource,
            Expression<Func<Control, object>> controlExpression,
            Expression<Func<T, object>> objectExpression,
            bool formattingEnabled)
    {
        string controlPropertyName = ProcessExpression(controlExpression.Body);
        string bindingTargetName = ProcessExpression(objectExpression.Body);

        return dataBindings
            .Add(controlPropertyName, dataSource, bindingTargetName, formattingEnabled);
    }

    public static Binding Add<T, K>
        (this ControlBindingsCollection dataBindings,
            object dataSource,
            Expression<Func<K, object>> controlExpression,
            Expression<Func<T, object>> objectExpression)
    {
        return Add(dataBindings, dataSource, controlExpression, objectExpression, false);
    }

    public static Binding Add<T, K>
        (this ControlBindingsCollection dataBindings,
            object dataSource,
            Expression<Func<K, object>> controlExpression,
            Expression<Func<T, object>> objectExpression,
            bool formattingEnabled
        )
    {
        string controlPropertyName = ProcessExpression(controlExpression.Body);
        string bindingTargetName = ProcessExpression(objectExpression.Body);

        return dataBindings.Add(controlPropertyName, dataSource, bindingTargetName, formattingEnabled);
    }

    private static string ProcessExpression(Expression expression)
    {
        string propertyName;
        if (expression is MemberExpression)
        {
            propertyName = ((MemberExpression) (expression)).Member.Name;
        }
        else if (expression is UnaryExpression)
        {
            propertyName = ((MemberExpression) ((UnaryExpression) (expression)).Operand).Member.Name;
        }
        else
        {
            throw new InvalidOperationException(
                "Unknown expression type error in DataBindingsExtensionMethods.Add<T, K>");
        }
        return propertyName;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我可以像这样设置一个DataBinding:

txtBoundInt.DataBindings.Add<Contact>
    (bindingSource, tb => tb.Text, contact => contact.Id);
Run Code Online (Sandbox Code Playgroud)

或这个:

cboBoundSelectedItem.DataBindings.Add
            <Contact, ComboBox>
            (bindingSource, cbo => cbo.SelectedItem, con => con.ContactType)
Run Code Online (Sandbox Code Playgroud)

尽管如此,似乎还有很多表达方式.有没有更好的办法?


编辑:我确实找到了一个更好的方法,但是我把这个问题改成了答案我遇到了麻烦 - 下面由@Carl_G转载.

Xav*_*nas 6

将返回类型设置为对象怎么样?

public static Binding Add<T>
    (this ControlBindingsCollection dataBindings, object dataSource,
    Expression<Func<Control, object>> controlLambda,
    Expression<Func<T, object>> objectLambda) {
    string controlPropertyName =
          ((MemberExpression)(controlLambda.Body)).Member.Name;
    string bindingTargetName =
          ((MemberExpression)(objectLambda.Body)).Member.Name;

    return dataBindings.Add
         (controlPropertyName, dataSource, bindingTargetName);
}
Run Code Online (Sandbox Code Playgroud)


Car*_*l G 6

由于问题已编辑为仅包含答案,我在此处包含该答案.作者可能应该单独留下原始问题并回答他自己的问题.但它似乎是一个非常好的解决方案.


编辑:我更喜欢这个我最终在Google缓存中找到的解决方案(它已从作者的网站上删除),因为它只需要一种类型规范.我不知道为什么原作者删除了它.

// Desired call syntax:
nameTextBox.Bind(t => t.Text, aBindingSource, (Customer c) => c.FirstName);

// Binds the Text property on nameTextBox to the FirstName property
// of the current Customer in aBindingSource, no string literals required.

// Implementation.

public static class ControlExtensions
{
    public static Binding Bind<TControl, TDataSourceItem>
        (this TControl control, 
         Expression<Func<TControl, object>> controlProperty, 
         object dataSource, 
         Expression<Func<TDataSourceItem, object>> dataSourceProperty)
         where TControl: Control
    {
        return control.DataBindings.Add
             (PropertyName.For(controlProperty), 
              dataSource, 
              PropertyName.For(dataSourceProperty));
    }
}

public static class PropertyName
{
    public static string For<T>(Expression<Func<T, object>> property)
    {
        var member = property.Body as MemberExpression;
        if (null == member)
        {
            var unary = property.Body as UnaryExpression;
            if (null != unary) member = unary.Operand as MemberExpression;
        }
        return null != member ? member.Member.Name : string.Empty;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • SO有一个问答形式.它的设计方式使得具有相同问题/问题的人可以搜索他们所拥有的问题/问题,然后从中获益或提出解决方案.我对具有不同风格偏好的不同用户持开放态度,但我强烈反对您完全删除原始问题.您替换它的答案现在缺少问题为其提供的所有上下文.这样做不仅违背SO的设计,而且还使其他人更难从这里包含的信息中受益. (3认同)