强类型的Windows窗体数据绑定

时间:2010-08-09 21:17:19

标签: c# winforms data-binding functional-programming

我正在研究使用扩展方法的强类型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;
    }
}

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

txtBoundInt.DataBindings.Add<Contact>
    (bindingSource, tb => tb.Text, contact => contact.Id);

或者这个:

cboBoundSelectedItem.DataBindings.Add
            <Contact, ComboBox>
            (bindingSource, cbo => cbo.SelectedItem, con => con.ContactType)

虽然似乎有很多表达方式正在进行中。还有更好的方法吗?


编辑:我确实找到了一个更好的方法,但是我将这个问题更改为答案时遇到了麻烦 - @ reproduced below来自@Carl_G。

3 个答案:

答案 0 :(得分:6)

如何将返回类型设置为object?

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);
}

答案 1 :(得分:6)

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


编辑:我更喜欢这个我最终找到in Google's cache的解决方案(它已从author's site删除),因为它只需要一个类型规范。我不知道为什么原作者删除了它。

// 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;
    }
}

答案 2 :(得分:2)

我一直在使用Stuart发布的代码几个月了。我确实添加了一些重载来匹配你可能想要使用的其他数据绑定方案(我只是在这里发布,让其他人更容易让这个非常有用的工作)

    public static class ControlExtensions {

    /// <summary>Databinding with strongly typed object names</summary>
    /// <param name="control">The Control you are binding to</param>
    /// <param name="controlProperty">The property on the control you are binding to</param>
    /// <param name="dataSource">The object you are binding to</param>
    /// <param name="dataSourceProperty">The property on the object you are binding to</param>
    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 Binding Bind<TControl, TDataSourceItem>(this TControl control, Expression<Func<TControl, object>> controlProperty, object dataSource, Expression<Func<TDataSourceItem, object>> dataSourceProperty, bool formattingEnabled = false)
    where TControl :Control {
        return control.DataBindings.Add(PropertyName.For(controlProperty), dataSource, PropertyName.For(dataSourceProperty), formattingEnabled);
    }
    public static Binding Bind<TControl, TDataSourceItem>(this TControl control, Expression<Func<TControl, object>> controlProperty, object dataSource, Expression<Func<TDataSourceItem, object>> dataSourceProperty, bool formattingEnabled, DataSourceUpdateMode updateMode)
    where TControl :Control {
        return control.DataBindings.Add(PropertyName.For(controlProperty), dataSource, PropertyName.For(dataSourceProperty), formattingEnabled, updateMode);
    }
    public static Binding Bind<TControl, TDataSourceItem>(this TControl control, Expression<Func<TControl, object>> controlProperty, object dataSource, Expression<Func<TDataSourceItem, object>> dataSourceProperty, bool formattingEnabled, DataSourceUpdateMode updateMode, object nullValue)
    where TControl :Control {
        return control.DataBindings.Add(PropertyName.For(controlProperty), dataSource, PropertyName.For(dataSourceProperty), formattingEnabled, updateMode, nullValue);
    }
    public static Binding Bind<TControl, TDataSourceItem>(this TControl control, Expression<Func<TControl, object>> controlProperty, object dataSource, Expression<Func<TDataSourceItem, object>> dataSourceProperty, bool formattingEnabled, DataSourceUpdateMode updateMode, object nullValue, string formatString)
    where TControl :Control {
        return control.DataBindings.Add(PropertyName.For(controlProperty), dataSource, PropertyName.For(dataSourceProperty), formattingEnabled, updateMode, nullValue, formatString);
    }
    public static Binding Bind<TControl, TDataSourceItem>(this TControl control, Expression<Func<TControl, object>> controlProperty, object dataSource, Expression<Func<TDataSourceItem, object>> dataSourceProperty, bool formattingEnabled, DataSourceUpdateMode updateMode, object nullValue, string formatString, IFormatProvider formatInfo)
    where TControl :Control {
        return control.DataBindings.Add(PropertyName.For(controlProperty), dataSource, PropertyName.For(dataSourceProperty), formattingEnabled, updateMode, nullValue, formatString, formatInfo);
    }

    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;
        }
    }

}