2009-06-11 7 views
10

Ho un controllo utente con più campi che mi piacerebbe avere associato a BindingSource. Mi piacerebbe anche che UserControl esponga alcune proprietà BindingSource in modo che possa essere rilasciato su un modulo e associato a BindingSource nel modulo. C'è un modo semplice per farlo? Mi rendo conto che posso riassociare tutti i controlli di UserControl nel suo setter BindSource. Ma questo sembra sbagliato. Esiste un proxy BindingSource che consentirà di collegare BindingSource nel controllo utente a BindingSource nel modulo?Utilizzo di BindingSource in un UserControl

+0

Si potrebbe forse esporre la proprietà dell'oggetto BindingSource.DataSource scrivendo una proprietà che si chiamerà DataSource e ciò imposterà la proprietà BindingSource.DataSource del modulo. Altrimenti, per favore cerca di spiegare ulteriormente cosa vuoi fare o dare un esempio concreto che potrebbe aiutarci a capire meglio. È ancora un po 'confuso nella mia testa quando l'ho letto. Vuoi impostare DataSource in fase di progettazione? Vuoi esporre le proprietà BindingSource nella finestra Proprietà? Vuoi associare i controlli UserControl a un DataMember specifico da BindingSource 'n change on design? –

+3

Forse potresti accettare la risposta che gli altri forniscono alla tua domanda. Penso che questo sarebbe un buon modo per ringraziare coloro che hanno preso questo tempo per rispondere e aiutarti, se hanno aiutato o no, hanno preso questo tempo per te. –

+0

Utilizzare nomi completi quando si fa riferimento a oggetti e proprietà. Sii specifico, fornisci del codice o semplici esempi. Non aspettarti da noi di capire un contesto mancante. – profimedica

risposta

5

Secondo la tua domanda, difficilmente riesco a capire cosa intendi fare. Così cercherò di fare del mio meglio per fornirti, spero, informazioni interessanti su questo argomento.

Innanzitutto, consideriamo il seguente UserControl in un progetto software di gestione clienti.

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

In secondo luogo, consideriamo il seguente modulo che dovrebbe essere il modulo di gestione del cliente.

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

Se ci si aspetta di utilizzare la proprietà CustomerManagementUserControl.DataSource dalla finestra Proprietà, perche non aggiungendo il seguente in cima alla vostra definizione di proprietà.

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

Questo è un modo di fare ciò che immagino tu voglia fare. D'altra parte, se ciò che si desidera fare è ottenere il più astratto possibile impostando un diverso tipo di oggetto come proprietà UserControl.BindingSource.DataSource, allora si dovrà scrivere un metodo che possa rilevare il tipo di l'oggetto è passato, quindi ha vincolato le proprietà di conseguenza. Un buon modo per andare, forse, è con Reflection, se ti senti a tuo agio a lavorarci. In ogni modo possibile, immaginate di lavorare con tali caratteristiche di polimorfismo, dovrete scrivere voi stessi un'interfaccia che tutti i vostri oggetti associabili dovranno implementare. In questo modo, eviterete nomi di proprietà sconosciuti e quando arriverà il momento di associare i controlli di UserControl, sarete in grado di legare la proprietà corretta al controllo corretto e così via.

Proviamo il seguente:

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

Considerando il codice di cui sopra, è possibile utilizzare la proprietà DataSource del UserControl di legarsi con un IEntity, in modo che le proprietà potrebbe piacere come questo.

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

Detto questo, se si vuole spingere ancora di più, si può solo esporre i controlli DataBindings proprietà del UserControl, al fine di metterli in fase di progettazione. Considerando ciò, si vorrà esporre la propria BindingSource come proprietà pubblica in modo che sia possibile impostarla anche in fase di progettazione, quindi scegliere il DataMember da questa BindinSource.

Spero che questo ti aiuti sia un po 'o almeno, ti dà alcune tracce per ulteriori ricerche.

1

Se si voleva fare tutto questo automaticamente si potrebbe cercare la fonte associazione dal form padre in caso di carico di controllo utente o qualcosa del genere ...

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

Se si assegna lo stesso riferimento all'oggetto come origine dati su due collegamenti, i controlli non verranno aggiornati in modo coerente sulla seconda origine di bindings.Forse, un compromesso per le scelte di cui sopra è il seguente:

  1. temporaneamente aggiungere un BindingSource al UserControl e utilizzare il designer VS per impostare le associazioni ai controlli.
  2. portare il designer.vb nell'editor di codice. Cerca tutte le linee "DataBindings.Add" create dal designer. Copia tutti sul blocco note.
  3. eliminare la bindingsource dalla finestra di progettazione e aggiungere un riferimento di associazione nel codice. Aggiungere una proprietà per l'origine bindings con lo stesso nome utilizzato nel designer. Nel setter per la proprietà, incollare tutte le righe dal blocco note sopra nel passaggio 2.
  4. Nell'evento Load del modulo, assegnare l'origine di associazione del modulo alla proprietà sul controllo utente. Se il controllo utente è incorporato in un altro controllo utente, è possibile utilizzare l'evento handlecreated del controllo genitore per fare lo stesso.

C'è meno digitazione e meno errori di battitura perché il designer VS sta creando tutti quei nomi di proprietà di testo letterali.

1

So che è una risposta tardiva; tuttavia, potrebbe essere utile a qualcun altro che legge questo post.

Ho controlli su un UserControl che sono associati ai dati. Devo avere unosu UserControl per poter associare i controlli in fase di progettazione. Il "reale" BindingSource, tuttavia, si trova su Form. In altre parole, i controlli su UserControl dovrebbero comportarsi come se si trovassero direttamente sul modulo (o su un ContainerControl nel modulo).

L'idea alla base di questa soluzione è quello di guardare per la DataSourceChanged caso di "reale" BindingSource e di assegnare la sua DataSource al locale BindingSource quando cambia. Al fine di trovare la "vera" BindingSource ho lasciato il Form (o Control) che lo contiene implementare la seguente interfaccia:

public interface IDataBound 
{ 
    BindingSource BindingSource { get; } 
} 

possiamo guardare per la ParentChanged caso di controllo al fine di sapere quando è stata aggiunta a Form o a ContainerControl. Il problema qui è che questo ContainerControl stesso potrebbe non essere stato aggiunto allo Form (o un altro ContainerControl) in questo momento. In questo caso, ci iscriviamo all'evento ParentChanged dell'ultimo genitore che troviamo nella catena dei genitori e aspettiamo fino a quando questo ultimo genitore è stato aggiunto, e così via, finché non troviamo uno Control o Form che attua IDataBound. Quando è stato trovato uno IDataBound, ci iscriviamo all'evento DataSourceChanged del suo 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; 
    } 
}