2010-08-09 19 views
8

Estoy buscando en fuertes mecanografiados Windows Forms databinding utilizando métodos de extensión. He llegado hasta aquí después de la ayuda de Xavier de la siguiente manera:Fuerte tipo de Windows Forms databinding

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

Ahora puedo establecer una DataBinding así:

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

O esto:

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

No parece haber una gran cantidad de expresiones va pasando sin embargo. ¿Hay una mejor manera?


Editar: Lo que encontrar una mejor manera, pero tengo problemas para cambiar esta pregunta a la respuesta - es reproduced below por @Carl_G.

+0

Por favor, no modifique su pregunta en una respuesta. Si ha encontrado una solución, debe ir en la sección de respuestas. Para una persona que intenta navegar rápidamente por los enlaces de google para encontrar una solución, es muy desconcertante leer "Muy bien, encontré una solución" sin siquiera saber cuál era su pregunta, o poder evaluar si es aplicable al problema del visitante. –

+0

Oh, bueno, tengo que seguir las reglas ... – stuartd

+0

Cabe señalar que el nuevo nombre de la función() en C# 6 también podría utilizarse para evitar el uso de una cadena. https://msdn.microsoft.com/en-us/library/dn986596.aspx –

Respuesta

6

¿Qué pasa con la configuración del tipo de retorno a objetar?

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

Gracias: que compila, pero produce este error de tiempo de ejecución: No se puede convertir objeto de tipo 'System.Linq.Expressions.UnaryExpression' al tipo 'System .Linq.Expressions.MemberExpression '. – stuartd

+0

Hmm. Puedo emitir el objectLambda a un UnaryExpression, pero no puedo ver cómo obtener el nombre de la propiedad de la UnaryExpression .. (la controlLambda sigue siendo un MemberExpression) – stuartd

+0

Muchas gracias por su ayuda, eso es todo clavado ahora. – stuartd

2

He estado utilizando el código publicado por Stuart durante algunos meses. Hice añadir un poco más de sobrecargas para que coincida con el resto de los escenarios de enlace de datos que es posible que desee utilizar (yo sólo dejo aquí para que otros lo tienen un tiempo aún más fácil conseguir esta cosa muy útil de trabajo)

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

} 
+2

Este código funcionó bien. Sin embargo, necesita una pequeña solución. En lugar de restringir a un 'Control', debe estar restringido a 'IBindableComponent'. Esa es la interfaz adecuada que tiene la propiedad 'DataBindings'. – craigtadlock

4

Como la pregunta ha sido editada para incluir solo una respuesta, incluyo esa respuesta aquí. El autor probablemente debería haber dejado solo the original question y haber respondido su propia pregunta. Pero parece ser una muy buena solución.


Editar: Yo prefiero esta solución que encontré finalmente in Google's cache (se ha suprimido de la author's site), ya que sólo necesita una especificación de tipo. No sé por qué el autor original lo eliminó.

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

SO tiene un formato de pregunta-respuesta (s).Está diseñado de esa manera para que las personas con el mismo problema/pregunta puedan buscar problemas/preguntas que tengan, y luego se beneficien o sugieran soluciones. Estoy abierto a diferentes usuarios que tengan diferentes preferencias estilísticas, pero estoy totalmente en desacuerdo con que hayas eliminado por completo tu pregunta original. La respuesta con la que lo reemplazó ahora carece de todo el contexto que la pregunta proporciona para ello. Hacerlo no solo va en contra del diseño de SO, sino que también hace que sea más difícil para otros beneficiarse de la información contenida en este documento. –

+0

No, simplemente puso lo que era una respuesta en la ubicación correcta. Entonces, si alguien decide "está bien, creo que entiendo de qué se trata este problema, ahora voy a examinar las respuestas para ver si hay algunas buenas", pudieron ver la buena respuesta que usted había incluido. –

+0

¿Viste que devolví tu pregunta original al principio y luego tu respuesta fue después? (Y ahora solo la respuesta sigue siendo como la tuviste antes). Pensé que tal vez la habías revertido, pero tal vez un administrador la revirtió. No sé, solo estaba tratando de ayudar. –