Strong typed Windows Forms databinding
I am looking into strong typed Windows Forms databinding using extension methods. I have got this far following help from Xavier as below:
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>&开发者_开发问答gt; 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;
}
}
Now I can set up a DataBinding like this:
txtBoundInt.DataBindings.Add<Contact>
(bindingSource, tb => tb.Text, contact => contact.Id);
Or this:
cboBoundSelectedItem.DataBindings.Add
<Contact, ComboBox>
(bindingSource, cbo => cbo.SelectedItem, con => con.ContactType)
There seems to be a lot of casting of expressions going on though. Is there a better way?
Edit: I did find a better way, but I got into trouble for changing this question to that answer - it's reproduced below by @Carl_G.
What about setting the return type to 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);
}
As the question has been edited to only include an answer, I'm including that answer here. The author probably should have left the original question alone and posted an answer to his own question. But it appears to be a very good solution.
Edit: I prefer this solution I found eventually in Google's cache (it has been deleted from the author's site) as it only needs one type specification. I don't know why the original author deleted it.
// 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;
}
}
I have been using the code posted by Stuart for a few months now. I did add a few more overloads to match the rest of the databinding scenarios that you may want to use (I'm just posting it here for others to have an even easier time getting this very useful thing working)
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;
}
}
}
精彩评论