2009-06-11 10 views
10

Tôi có một UserControl với nhiều trường mà tôi muốn ràng buộc với một BindingSource. Tôi cũng muốn UserControl để lộ một số tài sản BindingSource để nó có thể được bỏ trên một Form và bị ràng buộc vào BindingSource trên biểu mẫu. Có cách nào làm dễ hơn không? Tôi nhận ra rằng tôi có thể rebind tất cả các điều khiển của UserControl trong BindSource setter của nó. Nhưng điều này có vẻ sai. Có một số BindingSource Proxy sẽ cho phép tôi liên kết BindingSource trong điều khiển người dùng với BindingSource trong biểu mẫu?Sử dụng một BindingSource trong UserControl

+0

Bạn có thể phơi bày thuộc tính đối tượng BindingSource.DataSource bằng cách viết thuộc tính bạn gọi DataSource và điều này sẽ đặt thuộc tính BindingSource.DataSource của biểu mẫu của bạn. Nếu không, hãy cố gắng giải thích thêm những gì bạn muốn làm hoặc đưa ra một ví dụ cụ thể có thể giúp chúng tôi hiểu rõ hơn. Nó vẫn còn hơi mờ trong đầu tôi khi tôi đọc nó. Bạn có muốn đặt DataSource trên thiết kế thời gian không? Bạn có muốn hiển thị các thuộc tính BindingSource trong cửa sổ Thuộc tính không? Bạn có muốn liên kết các điều khiển UserControl của bạn với một DataMember cụ thể từ sự thay đổi về thiết kế của BindingSource không? –

+3

Có lẽ bạn có thể chấp nhận câu trả lời mà những người khác cung cấp cho câu hỏi của bạn. Tôi nghĩ rằng đây sẽ là một cách hay để cảm ơn những người đã dành thời gian này để trả lời và giúp đỡ bạn, cho dù họ có giúp đỡ hay không, họ đã dành thời gian này cho bạn. –

+0

Vui lòng sử dụng tên đầy đủ khi bạn tham chiếu đến các đối tượng và thuộc tính. Cụ thể, đưa ra một số mã hoặc ví dụ đơn giản. Đừng mong đợi từ chúng tôi để hiểu một bối cảnh mất tích. – profimedica

Trả lời

5

Theo câu hỏi của bạn, tôi khó có thể có được những gì bạn định làm. Vì vậy, tôi sẽ cố gắng hết sức để cung cấp cho bạn, tôi hy vọng, thông tin thú vị về vấn đề đó.

Trước tiên, hãy xem xét UserControl sau đây trong dự án phần mềm quản lý khách hàng.

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

Thứ hai, hãy xem xét biểu mẫu sau đây phải là biểu mẫu quản lý khách hàng của bạn.

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

Nếu bạn đang mong để sử dụng tài sản CustomerManagementUserControl.DataSource từ bên trong cửa sổ tài sản, xin vui lòng cân nhắc việc thêm những điều sau đây trên đầu của định nghĩa tài sản của bạn.

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

Đây là một cách để làm những gì tôi đoán bạn có thể muốn làm. Mặt khác, nếu những gì bạn muốn làm là để có được càng trừu tượng càng tốt bằng cách thiết lập một loại đối tượng khác nhau như tài sản UserControl.BindingSource.DataSource của bạn, thì bạn sẽ phải viết một phương thức có thể phát hiện loại đối tượng được truyền, sau đó ràng buộc các thuộc tính cho phù hợp. Một cách tốt đẹp bạn có thể đi, có lẽ, là bởi Reflection, nếu bạn cảm thấy thoải mái khi làm việc với nó. Trong bất kỳ cách nào có thể bạn có thể tưởng tượng làm việc với các tính năng đa hình như vậy, bạn sẽ phải viết cho mình một giao diện mà tất cả các đối tượng bindable của bạn sẽ phải thực hiện. Bằng cách này, bạn sẽ tránh các tên thuộc tính không xác định, và khi nào sẽ đến lúc ràng buộc các điều khiển của UserControl, bạn sẽ có thể ràng buộc thuộc tính chính xác với điều khiển chính xác và vân vân.

Hãy thử như sau:

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

Xét đoạn mã trên, bạn có thể sử dụng thuộc tính DataSource của usercontrol của bạn để ràng buộc với một IEntity, vì vậy tài sản của bạn có thể thích như thế này.

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

Điều đó nói rằng, nếu bạn muốn đẩy xa hơn nữa, bạn chỉ có thể vạch trần điều khiển DataBindings tính của usercontrol của bạn để cài đặt chúng vào thời gian thiết kế. Xem xét điều này, bạn sẽ muốn để lộ BindingSource của bạn như là một tài sản công cộng, do đó bạn có thể đặt nó trên thiết kế thời gian quá, sau đó chọn DataMember của bạn từ BindinSource này.

Tôi hy vọng điều này sẽ giúp bạn một chút hoặc ít nhất, cung cấp cho bạn một số bản nhạc để tìm kiếm thêm.

1

Nếu bạn muốn làm điều này tất cả tự động bạn có thể tìm kiếm các nguồn ràng buộc từ form cha trong trường hợp tải trọng của điều khiển người dùng hoặc một cái gì đó như thế bạn ...

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

Nếu bạn gán cùng tham chiếu đối tượng làm nguồn dữ liệu trên hai bindingsources, các điều khiển sẽ không được cập nhật liên tục trên bindingsource thứ hai.Có thể, sự thỏa hiệp với các lựa chọn ở trên là như sau:

  1. Tạm thời thêm một bindingsource để người dùng kiểm soát và sử dụng thiết kế VS để đặt các ràng buộc với điều khiển.
  2. mang lại designer.vb trong trình chỉnh sửa mã. Tìm kiếm tất cả các dòng "DataBindings.Add" do nhà thiết kế tạo ra. Sao chép tất cả vào notepad.
  3. xóa bindingsource khỏi trình thiết kế và thêm tham chiếu bindingsource vào mã. Thêm thuộc tính cho bindingsource có cùng tên như đã được sử dụng trong trình thiết kế. Trong setter cho thuộc tính, dán tất cả các dòng từ notepad ở trên trong bước 2.
  4. Trong trường hợp Tải biểu mẫu, gán bindingsource của biểu mẫu cho thuộc tính trên điều khiển người dùng. Nếu điều khiển người dùng được nhúng trong một điều khiển người dùng khác, bạn có thể sử dụng sự kiện handlecreated của kiểm soát cha để làm như vậy.

Có ít kiểu nhập và ít lỗi chính tả hơn vì nhà thiết kế VS đang tạo tất cả các tên thuộc tính văn bản theo ngữ cảnh đó.

1

Tôi biết đó là câu trả lời muộn; tuy nhiên, nó có thể hữu ích cho người khác đọc bài đăng này.

Tôi có các điều khiển trên UserControl bị ràng buộc dữ liệu. Tôi cần phải có một BindingSource trên UserControl để có thể ràng buộc các điều khiển tại thời gian thiết kế. Tuy nhiên, "thực" BindingSource nằm trên số Form. Nói cách khác, các điều khiển trên UserControl sẽ hoạt động như thể họ đang ngồi trực tiếp trên biểu mẫu (hoặc trên ContainerControl trên biểu mẫu).

Ý tưởng đằng sau giải pháp này là để theo dõi sự kiện DataSourceChanged của "thực" BindingSource và gán DataSource cho địa phương BindingSource khi thay đổi. Để tìm ra "thực" BindingSource tôi để cho các Form (hoặc Control) chứa nó thực hiện giao diện sau:

public interface IDataBound 
{ 
    BindingSource BindingSource { get; } 
} 

Chúng ta có thể theo dõi các sự kiện ParentChanged của một điều khiển để biết khi nào nó đã được thêm vào đến số Form hoặc ContainerControl. Vấn đề ở đây là bản thân số ContainerControl này có thể chưa được thêm vào số Form (hoặc ContainerControl) khác tại thời điểm này. Trong trường hợp này, chúng tôi đăng ký sự kiện ParentChanged của phụ huynh cuối cùng mà chúng tôi tìm thấy trong chuỗi phụ huynh và chờ cho đến khi phụ huynh cuối cùng này được thêm vào, cho đến khi chúng tôi tìm thấy Control hoặc Form triển khai IDataBound. Khi tìm thấy IDataBound, chúng tôi đăng ký sự kiện DataSourceChanged của sự kiện 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; 
    } 
}