2009-06-11 15 views
10

Tengo un UserControl con varios campos que me gustaría vincular a un BindingSource. También me gustaría que el UserControl exponga alguna propiedad de BindingSource para que se pueda descartar en un Formulario y vincularlo a BindingSource en el formulario. ¿Hay una forma fácil de hacer esto? Me doy cuenta de que puedo vincular todos los controles del UserControl en su setter BindSource. Pero esto parece estar mal. ¿Hay algún BindingSource Proxy que me permita vincular BindingSource en el control de usuario a BindingSource en el formulario?Uso de un BindingSource en un UserControl

+0

Quizás exponer su propiedad de objeto BindingSource.DataSource escribiendo una propiedad que llamaría DataSource, y esto establecería la propiedad BindingSource.DataSource de su formulario. De lo contrario, intente explicar con más detalle lo que desea hacer o dar un ejemplo concreto que pueda ayudarnos a comprender mejor. Todavía lo tengo un poco borroso cuando lo leo. ¿Desea configurar el DataSource en tiempo de diseño? ¿Desea exponer las propiedades de BindingSource en la ventana de Propiedades? ¿Desea vincular los controles de UserControl a un DataMember específico de su BindingSource 'n change on design? –

+3

Quizás podría aceptar la respuesta que los demás le dieron a su pregunta. Creo que esta sería una buena forma de agradecer a aquellos que se tomaron este tiempo para responder y ayudarlo, ya sea que ayudaran o no, se tomaron este tiempo para usted. –

+0

Utilice nombres completos cuando se refiera a objetos y propiedades. Sea específico, proporcione algún código o ejemplos simples. No espere de nosotros entender un contexto perdido. – profimedica

Respuesta

5

Según su pregunta, apenas puedo obtener lo que piensa hacer. Por lo tanto, haré todo lo posible para proporcionarle, espero, información interesante sobre ese asunto.

En primer lugar, consideremos el siguiente UserControl en un proyecto de software de gestión de clientes.

public partial class CustomerManagementUserControl : UserControl { 
    public CustomerManagementUserControl() { 
     InitializeComponent(); 
     _customerBindingSource = new BindingSource(); 
    } 
    public IList<ICustomer> DataSource { 
     set { 
      _customerBindingSource.DataSource = value; 
     } 
    } 
    private BindingSource _customerBindingSource; 
} 

En segundo lugar, consideremos el siguiente Formulario que debe ser su formulario de gestión de clientes.

public partial class CustomerManagementForm : Form { 
    public CustomerManagementForm() { 
     InitializeComponent(); 
     _customerUserControl = new CustomerManagementUserControl(); 
     _customerUserControl.Name = @"customerUserControl"; 
    } 
    private void CustomerManagementForm_Load(object sender, EventArgs e) { 
     // CustomersFacade is simply a static class providing customer management features and requirements. 
     // Indeed, the GetCustomers() method shall return an IList<ICustomer>. 
     // The IList type and typed IList<T> are both intended to be bindable as a DataSource for DataBinding. 
     _customerUserControl.DataSource = CustomersFacade.GetCustomers(); 
     this.Controls.Add(_customerUserControl); 
    } 
    private CustomerManagementUserControl _customerUserControl; 
} 

Si usted está esperando para usar la propiedad CustomerManagementUserControl.DataSource desde dentro de la ventana de propiedades, por favor considerar agregar el siguiente en la parte superior de la definición de la propiedad.

[System.ComponentModel.DesignTimeVisible(true), System.ComponentModel.DesignerCategory("CustomerUserControl"), System.ComponentModel.Description("Sets the CustomerUserControl DataSource property")] 

Esta es una forma de hacer lo que supongo que podría querer hacer. Por otro lado, si lo que desea hacer es obtener lo más abstracto posible configurando un tipo diferente de objeto como su propiedad UserControl.BindingSource.DataSource, tendrá que escribir un método que pueda detectar el tipo de objeto. el objeto pasado, luego vincula las propiedades en consecuencia. Una buena manera en que podría ir, tal vez, es Reflexión, si se siente cómodo trabajando con ella. De cualquier modo que pueda imaginar trabajando con tales características de polimorfismo, tendrá que escribir usted mismo una interfaz que todos sus objetos enlazables deberán implementar. De esta forma, evitará los nombres de propiedad desconocidos, y cuando llegue el momento de vincular los controles de UserControl, podrá enlazar la propiedad correcta con el control correcto, y así sucesivamente.

Probemos el siguiente:

public interface IEntity { 
    double Id { get; set; } 
    string Number { get; set; } 
    string Firstname { get; set; } 
    string Surname { get; set; } 
    long PhoneNumber { get; set; } 
} 
public interface ICustomer : IEntity { 
} 
public interface ISupplier : IEntity { 
    string Term { get; set; } 
} 
public sealed Customer : ICustomer { 
    public Customer() { 
    } 
    public double Id { get; set; } 
    public string Number { get; set; } 
    public string Firstname { get; set; } 
    public string Surname { get; set; } 
    public long PhoneNumber { get; set; }  
} 
public sealed Supplier : ISupplier { 
    public Supplier() { 
    } 
    public double Id { get; set; } 
    public string Number { get; set; } 
    public string Firstname { get; set; } 
    public string Surname { get; set; } 
    public long PhoneNumber { get; set; }  
    public string Term { get; set; } 
} 

Teniendo en cuenta el código anterior, puede utilizar la propiedad DataSource de su UserControl para unirse con un IEntity, por lo que su propiedad podría recibir como este.

[System.ComponentModel.DesignTimeVisible(true), System.ComponentModel.DesignerCategory("CustomerUserControl"), System.ComponentModel.Description("Sets the CustomerUserControl DataSource property")] 
public IList<IEntity> DataSource { 
    set { 
     _customerBindingSource.DataSource = value; 
    } 
} 

Dicho esto, si desea ir aún más lejos, usted podría exponer a los controles DataBindings las propiedades de su UserControl con el fin de ponerlos en tiempo de diseño. Teniendo esto en cuenta, querrá exponer su BindingSource como una propiedad pública para que también pueda configurarlo en tiempo de diseño, luego elija su DataMember de este BindinSource.

Espero que esto los ayude un poco o al menos, le proporcione algunas pistas para futuras búsquedas.

1

Si quería hacer todo esto de forma automática podría buscar el origen de enlace desde el formulario principal en el evento de carga de su control de usuario o algo por el estilo ...

Dim components As Reflection.FieldInfo = typ.GetField("components", Reflection.BindingFlags.DeclaredOnly Or Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic) 

Dim lstBindingSources As New List(Of BindingSource) 
For Each obj As Object In components.Components 
    Dim bindSource As BindingSource = TryCast(obj, BindingSource) 
    If bindSource IsNot Nothing Then 
     lstBindingSources.Add(bindSource) 
    End If 
Next 
If lstBindingSources.Count = 1 Then 
    MyBindingSource.DataSource = lstBindingSources(0).DataSource 
End If 
1

Si asigna el mismo referencia de objeto como origen de datos en dos fuentes de enlace, los controles no se actualizarán de forma coherente en el segundo origen de enlace.Posiblemente, un compromiso de las opciones anteriores es el siguiente:

  1. añadir temporalmente un BindingSource al control de usuario y utilizar el diseñador VS a establecer los enlaces a los controles.
  2. trae el designer.vb en el editor de código. Busque todas las líneas "DataBindings.Add" que fueron creadas por el diseñador. Cópialos todos en el bloc de notas.
  3. elimine el bindingsource del diseñador y agregue una referencia de bindingsource en el código. Agregue una propiedad para el bindingsource con el mismo nombre que se utilizó en el diseñador. En el colocador de la propiedad, pegue todas las líneas del Bloc de notas anterior en el paso 2.
  4. En el evento Cargar del formulario, asigne el origen de enlace del formulario a la propiedad en el control de usuario. Si el control del usuario está incrustado en otro control de usuario, puede usar el evento del control padre generado a mano para hacer lo mismo.

Hay menos tipado y menos errores tipográficos porque el diseñador VS está creando todos los nombres de propiedad de texto literal.

1

Sé que es una respuesta tardía; sin embargo, podría ser útil para alguien más leyendo esta publicación.

Tengo controles en un UserControl vinculados a datos. Necesito tener un BindingSource en el UserControl para poder enlazar los controles en el momento del diseño. El "verdadero" BindingSource, sin embargo, se encuentra en el Form. En otras palabras, los controles en el UserControl deben comportarse como si estuvieran sentados directamente en el formulario (o en un ContainerControl en el formulario).

La idea detrás de esta solución es mirar para el DataSourceChanged caso de la "real" BindingSource y asignar su DataSource a la BindingSource locales cuando cambia. Con el fin de encontrar el "verdadero" BindingSource dejo que el Form (o Control) que lo contiene implementar la siguiente interfaz:

public interface IDataBound 
{ 
    BindingSource BindingSource { get; } 
} 

Podemos mirar para el ParentChanged caso de un control con el fin de saber cuándo se ha añadido a Form o ContainerControl. El problema aquí es que este ContainerControl podría no haberse agregado al Form (u otro ContainerControl) aún en este momento. En este caso, nos suscribimos al evento ParentChanged del último padre que encontramos en la cadena de padres y esperamos hasta que este último padre haya sido agregado, y así sucesivamente, hasta que encontremos un Control o Form implementando IDataBound. Cuando se ha encontrado un IDataBound, nos suscribimos al evento DataSourceChanged de su BindingSource.

public partial class MyUserControl : UserControl 
{ 
    private IDataBound _dataBoundControl; 
    private Control _parent; 

    public MyUserControl() 
    { 
     InitializeComponent(); 
     if (LicenseManager.UsageMode == LicenseUsageMode.Runtime) { 
      _parent = this; 
      SearchBindingSource(); 
     } 
    } 

    private void SearchBindingSource() 
    { 
     if (_parent != null && _dataBoundControl == null) { 
      while (_parent.Parent != null) { 
       _parent = _parent.Parent; 
       _dataBoundControl = _parent as IDataBound; 
       if (_dataBoundControl != null) { 
        if (_dataBoundControl.BindingSource != null) { 
         _dataBoundControl.BindingSource.DataSourceChanged += 
          new EventHandler(DataBoundControl_DataSourceChanged); 
        } 
        return; 
       } 
      } 
      // This control or one of its parents has not yet been added to a 
      // container. Watch for its ParentChanged event. 
      _parent.ParentChanged += new EventHandler(Parent_ParentChanged); 
     } 
    } 

    void Parent_ParentChanged(object sender, EventArgs e) 
    { 
     SearchBindingSource(); 
    } 

    void DataBoundControl_DataSourceChanged(object sender, EventArgs e) 
    { 
     localBindingSource.DataSource = _dataBoundControl.BindingSource.DataSource; 
    } 
} 
Cuestiones relacionadas