【问题标题】:Strong typed Windows Forms databinding强类型 Windows 窗体数据绑定
【发布时间】:2010-08-09 21:17:18
【问题描述】:

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

不过,似乎有很多表达式的转换。有没有更好的办法?


编辑:我确实找到了一个更好的方法,但是我把这个问题改成那个答案时遇到了麻烦——@Carl_G 的reproduced below。

【问题讨论】:

  • 请不要将您的问题修改为答案。如果您找到了解决方案,则需要进入答案部分。对于试图快速浏览 google 链接以寻求解决方案的人来说,在不知道您的问题是什么或无法评估它是否适用于访问者的问题的情况下阅读“好的,我找到了解决方案”是非常令人迷惑的。
  • 哦,好吧,必须遵守规则..
  • 需要注意的是,C# 6 中新的 nameof() 函数也可以用来避免使用字符串。 msdn.microsoft.com/en-us/library/dn986596.aspx

标签: c# winforms data-binding


【解决方案1】:

将返回类型设置为对象呢?

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

【讨论】:

  • 谢谢:编译,但产生此运行时错误:无法将类型为“System.Linq.Expressions.UnaryExpression”的对象转换为类型“System.Linq.Expressions.MemberExpression”。
  • 嗯。我可以将 objectLambda 转换为 UnaryExpression,但我看不到如何从 UnaryExpression 中获取属性名称。(controlLambda 仍然是 MemberExpression)
  • 异常Unable to cast object of type 'System.Linq.Expressions.UnaryExpression' to type 'System.Linq.Expressions.MemberExpression'. 通常发生在您的函数中不再有类型时,例如当您有Expression&lt;Func&lt;T, int&gt;&gt; ... x -&gt; x.ID 和x.ID 实际上是long 类型时。
【解决方案2】:

由于问题已被编辑为仅包含答案,因此我将在此处包含该答案。作者可能应该单独离开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;
    }
}

【讨论】:

  • SO 有问答格式。它是这样设计的,因此有相同问题/问题的人可以搜索他们遇到的问题/问题,然后从中受益或提出解决方案。我对具有不同风格偏好的不同用户持开放态度,但我强烈不同意您完全删除原始问题。您替换它的答案现在缺少问题为其提供的所有上下文。这样做不仅违背了 SO 的设计,而且还使其他人更难以从此处包含的信息中受益。
  • 不,它只是将答案放在正确的位置。因此,如果有人决定“好吧,我想我明白这个问题是关于什么的,现在我要扫描答案,看看是否有好的答案”,他们可以看到你提供的好的答案。
  • 你有没有看到我把你原来的问题放回了开头,然后你的答案就在后面了? (现在只有答案仍然像以前一样。)我想也许你已经恢复了它,但也许管理员恢复了它。我不知道,我只是想帮忙。
  • 我说的第一件事是我从不再是问题的问题中复制了我的答案内容。我真的不明白你的意思。
  • 对不起。在我急于阅读您的回复时,我错过了该问题已被回复(您实际上说过,我误解了。)我认为您包含的解决方案必须保持某种形式,因为它是一个很好的解决方案。如果您想在自己的帐户下发布,请这样做,然后我也可以删除我的答案。我只是希望人们从如此的爱情三明治中受益。还记得谷歌搜索编程问题只返回付费墙后面的专家交流响应的可怕日子吗?
【解决方案3】:

几个月来,我一直在使用 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;
        }
    }

}

【讨论】:

  • 这段代码运行良好。不过,它需要一个小修复。不应将其限制为“控件”,而应将其限制为“ IBindableComponent”。这是具有“DataBindings”属性的正确接口。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-11
  • 2017-02-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多