Windows Develop Bookmark and Share   
 index > Windows Forms Data Controls and Databinding > Binding in a compound UserControl
 

Binding in a compound UserControl

Gentlemen

I have a user-control which hosts many other data bound controls. I intend to re-sue this user-control throughout my application.
The hole purpose of this post is to ask if anyone has experience in re-binding controls in a user-control to another BindingSource.

The purpose of the user-control is to select a customer from a list, and then select a contact associated with that customer.
The Customer business object contains a list of contacts.

This information is then stored in an invoice header: the customer and the selected contact.

Within the user-control I have the following binding sources.
bindingSourcCustomers : The source list of customers - bound at design time to typeof(Customer)
bindingsourceContacts : List of contacts - bound to bindingSourceCustomers with the data member set to the Contacts list

bindingSourceInvoiceHeader : The invoice header we wish to store the customer and contact into - bound at design time to typeof(invoiceHeader)

I use these binding sources to set all the bound properties at design time:
There is one combo which chooses the customer and stores it result in bindingSourceInvoiceHeader.Customer
and another combo which stores the selected contact to bindingSourceInvoiceHeader.Contact

As I mentioned before, I want to place this user-control on another form, and re-bind to a binding source on the main form: to explain.
I'll place this user control, on my invoice editing form. This form will have a binding source for all customers, and a binding source for invoice headers.

I have played with adding a couple of BindingSource properties to my user-control, and when the value changes I run through all the controls on the user form and re-create the bindings - a little messy I feel.

		/// <summary><br/>
		/// Re-bind controls to a new binding source.<br/>
		/// </summary><br/>
		/// <param name="sourceControl">Container control</param><br/>
		/// <param name="newSource">New binding soruce</param><br/>
		public BindingSource RebindControls(Control sourceControl, BindingSource newSource)<br/>
		{<br/>
			if (newSource == null) return null;<br/>
<br/>
			foreach (Control control in sourceControl.Controls)<br/>
			{<br/>
				ControlBindingsCollection myBindings = control.DataBindings;<br/>
				List<Binding> newBindings = new List<Binding>();<br/>
				foreach (Binding myBinding in myBindings)<br/>
				{<br/>
					if ((myBinding.DataSource == myBinding.DataSource))<br/>
					{<br/>
						Binding newBinding = new Binding(myBinding.PropertyName, newSource, myBinding.BindingMemberInfo.BindingMember,<br/>
														 myBinding.FormattingEnabled, myBinding.DataSourceUpdateMode, myBinding.NullValue,<br/>
														 myBinding.FormatString, myBinding.FormatInfo);<br/>
						newBindings.Add(newBinding);<br/>
					}<br/>
				}<br/>
				control.DataBindings.Clear();<br/>
				foreach (Binding myBinding in newBindings)<br/>
				{<br/>
					control.DataBindings.Add(myBinding);<br/>
				}<br/>
			}<br/>
			return newSource;<br/>
		}<br/>


There are problems with this.

So (Apologies for the over details)

Does anyone know of an elegant way of re-assigning bindings.
I know I can do it through code, by assigning control bindings programmatically, but I feel the doing it all at design time, and re-assigning is neater.

Is there any way of synchronising two binding sources (Should I be looking at currency manager or binding manager)

Again - sorry for the length of this post, and thanks for your time.



Stovesy  Friday, June 12, 2009 9:42 AM
Ouch....

I can set the (private)currencyManager property of the BindingSources !
This synchronises two separate binding sources.
{
	SetPrivateMemberRefType(ref userControlTest1.bindingSourceCustomer, "currencyManager", bindingSourceCustomerLeft.CurrencyManager);
	SetPrivateMemberRefType(ref userControlTest1.bindingSourceContacts, "currencyManager", bindingSourceContacts.CurrencyManager);
}


//used to set private values in classes
public static void SetPrivateMemberRefType<TObjectType, TValueType>(ref TObjectType o, string variableName, TValueType value)
{
	Type t = o.GetType();
	FieldInfo fi = t.GetField(variableName, BindingFlags.NonPublic | BindingFlags.Instance);
	if (fi != null)
	{
		fi.SetValue(o, value);
	}
}

Wonder if this is bad ?
Stovesy  Friday, June 12, 2009 11:54 AM
Hi Stovesy,

Did you want to synchronize two bindingsources or just rebind the usercontrol to different DataSource?

Best regards,
Bruce Zhou
Please mark the replies as answers if they help and unmark if they don't.
Bruce.Zhou  Tuesday, June 16, 2009 1:02 PM
I been puzzled with the same problem for days and can't believe I don't find any proper references on the web on how to do this.

Instead of rebinding the best solution I came up with for the moment issynchronizingthe BindingSource in the UserControl with the one on the form.

I will briefly repeat the scenario: A ChildUserControl uses a BindingSource to databind the controls it contains at design time. This ChildUserControl is then inserted into a Form where it is somehow bound to another BindingSource specified in that form. We need the controls in the ChildUserControl to be able to bind to the data in the form's BindingSource (instead of loading their own separate copy of the same data).

So what I roughly do is this:

    public partial class ChildUserControl : UserControl
    {
        public ChildUserControl()
        {
            InitializeComponent();

            // Hook a handler to the CurrentChanged event of the ChildBindingSource 
            // so that we get a chance to synchronize the ParentBindingSource with it.
            ChildBindingSource.CurrentChanged += new EventHandler(ChildBindingSource_CurrentChanged);
        }

        /// <summary>
        /// Public property that can be used in the designer of the form to assign
        /// a BindingSource to the UserControl. 
        /// </summary>
        /// <remarks>
        /// I was tempted to name it DataSource
        /// but since I want to restric the type of datasource acceptable to BindingSource
        /// I decided to make the property name relevant to the type.
        /// </remarks>
        public BindingSource BindingSource
        {
            get { return ChildBindingSource.DataSource as BindingSource; }
            set
            {
                if (ChildBindingSource.DataSource != value)
                {
                    ChildBindingSource.DataSource = value;

                    // Hook a handler to the CurrentChanged event of the ParentBindingSource 
                    // so that we get a chance to synchronize the ChildBindingSource with it.
                    value.CurrentChanged += new EventHandler(ParentBindingSource_CurrentChanged);
                }
            }
        }

        /// <summary>
        /// Gets the BindingSource of the Form.
        /// </summary>
        /// <remarks>
        /// Returns the BiningSource property. It has only been added for clarity in the code.
        /// </remarks>
        private BindingSource ParentBindingSource
        {
            get { return BindingSource; }
        }

        /// <summary>
        /// Gets the BindingSource of this UserControl.
        /// </summary>
        /// <remarks>
        /// Returns the bindingSource field. It has only been added for clarity in the code.
        /// The bindingSource field is just a private field added by the designer when I dropped 
        /// a BindingSource on the design surface. It is used as a base for data binding all the 
        /// controls in the UserControl in the designer.
        /// </remarks>
        private BindingSource ChildBindingSource
        {
            get { return bindingSource; }
        }

        /// <summary>
        /// Handles the CurrentChanged event of the ParentBindingSource.
        /// </summary>
        /// <remarks>
        /// This will move the pointer of the ChildBindingSource to the same position
        /// as the one on the ParentBindingSource.
        /// </remarks>
        private void ParentBindingSource_CurrentChanged(object sender, EventArgs e)
        {
            if (ParentBindingSource != null && ChildBindingSource.Position != ParentBindingSource.Position)
                ChildBindingSource.Position = ParentBindingSource.Position;
        }

        /// <summary>
        /// Handles the CurrentChanged event of the ChildBindingSource.
        /// </summary>
        /// <remarks>
        /// This will move the pointer of the ParentBindingSource to the same position
        /// as the one on the ChildBindingSource.
        /// </remarks>
        private void ChildBindingSource_CurrentChanged(object sender, EventArgs e)
        {
            if (ParentBindingSource != null && ParentBindingSource.Position != ChildBindingSource.Position)
                ParentBindingSource.Position = ChildBindingSource.Position;
        }

    }



I was hoping there was a nice way to do this with even less code and mainly just one BindingSource (the one on the form).

All suggestions are welcome...

Yannis

.rousso
  • Edited byrousso Tuesday, September 22, 2009 1:17 PMtypo
  •  
rousso  Tuesday, September 22, 2009 1:15 PM

You can use google to search for other answers

Custom Search

More Threads

• How to prevent adding new row in child rows of datagrid
• Enterprise Library 2006 and TableAdapters
• Collection of business objects implementing IEditableObject and "ReadOnly" DataGrid
• Table adapter user defined query possible ??
• datagridview - manual update
• DataGridView CellPainting
• datagridview with combobox column
• I get an error to filter bindingsouerce
• CrystalReports.NET "Microsoft Development Environment has encountered a problem and needs to close" error
• Overriding DataAdapter Update Method