UserControl and BindingContext

M

MeowCow

I have created a UserControl that encapsulates a third party data grid.
My goal was to create my own DataSource and DataMember properties that
forward the binding to the third party grid, then use binding like
normal.

The problem I am running into is that my UserControl ends up with a
different BindingContext then the ParentForm it is contained in and
thus all other controls on the parent form. (I want various controls
on the form to update as I move between rows in the grid).

As far as I can tell the BindingContext of my user control and the
underlying third party grid get set when the DataSource property is
set. The DataSource property is set before the UserControl is added to
the controls collection on the ParentForm.

I would like my UserControl to use the same BindingContext as the
ParentForm. Does anyone know how to accomplish this so that my
DataSource and is connected to the ParentForm BindingContext?


Any help is appreciated, would gladly post code snippets or clarify any
questions.
~ Adam dR.
 
D

Dave Sexton

Hi,

In order for the BindingContext to be the same, assuming that the
third-party data-bound control is behaving properly, the DataSource and
DataMember properties of the data-bound control have to be the same as the
values passed to the BindingContext indexer:

yourControl.DataMember = dataMember;
yourControl.DataSource = dataSource;

// "this" is the Form
context = this.BindingContext[dataSource, dataMember];

It shouldn't matter whether the DataSource property of the data-bound
control is set before or after being added to the Form's Controls
collection.

If you are using property bindings for controls on the Form then the data
source must be the same but the member can be different:

txtName.DataBindings.Add("Text", dataSource, "FirstName");

The line above will automatically update the Text property with the
"FirstName" value of the current dataSource record.

If the dataSource to which you are binding the UserControl is a DataSet,
then the data member is probably the name of a DataTable. In that case, you
must specify the name of the DataTable as well in the txtName Binding
otherwise the contexts will be different:

txtName.DataBindings.Add("Text", dataSource, "People.FirstName");

"People" is required since dataSource is only equal to the DataSet, not the
specific data member.

If the dataSource to which you are binding the UserControl is a DataTable,
then "People." isn't necessary in the Binding above and the original example
should work just fine.

The point is that both the data source and data member of the Binding has to
evaluate to the same values being used by the DataSource and DataMember
properties of the UserControl, respectively, with the addition of a column
name such as "FirstName" being allowed in the member as well.

You may want to supply some code if this doesn't help you at all.

"BindingContext Class"
http://msdn2.microsoft.com/en-us/library/system.windows.forms.bindingcontext.aspx
 
B

Bart Mermuys

Hi,

I have created a UserControl that encapsulates a third party data grid.
My goal was to create my own DataSource and DataMember properties that
forward the binding to the third party grid, then use binding like
normal.

The problem I am running into is that my UserControl ends up with a
different BindingContext then the ParentForm it is contained in and
thus all other controls on the parent form. (I want various controls
on the form to update as I move between rows in the grid).

As far as I can tell the BindingContext of my user control and the
underlying third party grid get set when the DataSource property is
set. The DataSource property is set before the UserControl is added to
the controls collection on the ParentForm.

If a Controls BindingContext is null (or hasn't been set) then that Control
will look for a parent that has a non-null BindingContext and return that
one. If no parent can be found with a non-null BindingContext then null is
returned.

However both Form and UserControl inherit from ContainerControl. When
accessing the BindingContext of a ContainerControl it will create its own if
it was null and can't find one from a parent (instead of returning null).

So in your case the following is happening :
1) 3th party control DataSource/DataMember is being set
2) 3th party control wants to setup DataBinding and asks (itself) for a
BindingContext
3) Since no BindingContext has been explicitly set on the 3th party control,
it will ask the parent Control (which is your UserControl) for one
4) UserControl doesn't have a parent or a BindingContext set, so it creates
one ...

As for workarounds;

- You could explicitly assign the Forms BindingContext to the UserControls
BindingContext at any time, if the 3th party control behaves properly it
should notice this and rebind or

- you could override property BindingContext on your UserControl and make it
behave like a Control (not creating its own BindingContext), this means
BindingContext will return null until it's added to the ControlCollection,
again the 3th party control should behave properly and postpone its
databinding until a valid BindingContext becomes available, eg.:

public class SomeUserControl : UserControl
{
private BindingContext bindingContext;

public override BindingContext BindingContext
{
set
{
bindingContext = value;
OnBindingContextChanged(EventArgs.Empty);
}
get
{
// check if a BindingContext has been assigned
if ( bindingContext != null )
return bindingContext;

// check if we have a parent
if ( Parent != null )
return Parent.BindingContext;

// otherwise return null
return null;
}
}

protected override void OnParentBindingContextChanged(EventArgs e)
{
if ( bindingContext == null )
OnBindingContextChanged(EventArgs.Empty);
}
}

HTH,
greetings
 
D

Dave Sexton

Hi Bart,

Another workaround for when the DataSource property of the UserControl is
set before it's added to the Form's Controls collection is to bind to a
BindingSource object (in the 2.0 framework). The following code works just
fine, binding to a BindingSource, however binding directly to the DataSet or
DataTable doesn't unless DataSource is set after the UserControl is added to
the Controls collection of the Form:

private BindingSource dataSource;
private DataTable table;
private TextBox textBox;

public TestForm() // .ctor for TestForm : Form
{
UserControl userControl = new UserControl();
userControl.Location = new Point(10, 10);
userControl.Size = new Size(450, 450);

DataGridView grid = new DataGridView();
grid.Dock = DockStyle.Fill;

userControl.Controls.Add(grid);

DataSet data = new DataSet();
table = data.Tables.Add();
table.Columns.Add("String Value", typeof(string));

//grid.DataMember = "Table1";
//grid.DataSource = data;
//grid.DataSource = table;
grid.DataSource = dataSource = new BindingSource(data, "Table1");

textBox = new TextBox();
textBox.Location = new System.Drawing.Point(520, 26);
textBox.Size = new System.Drawing.Size(100, 20);

ClientSize = new System.Drawing.Size(712, 556);

Controls.Add(textBox);
Controls.Add(userControl);
}

protected override void OnLoad(EventArgs e)
{
// add test data
for (int i = 1; i < 6; i++)
table.Rows.Add("Row " + i);

//textBox.DataBindings.Add("Text", table.DataSet, "Table1.String
Value");
//textBox.DataBindings.Add("Text", table, "String Value");
textBox.DataBindings.Add("Text", dataSource, "String Value");

base.OnLoad(e);
}
 
B

Bart Mermuys

Hi,

Dave Sexton said:
Hi Bart,

Another workaround for when the DataSource property of the UserControl is
set before it's added to the Form's Controls collection is to bind to a
BindingSource object (in the 2.0 framework).

Yeah that's true, because a BindingSource owns its own CurrencyManager.

CurrencyManager cm = (CurrencyManager)someBindingContext[someBindingSource];

is the same as:

CurrencyManager cm = someBindingContext.CurrencyManager;

So it doesn't matter what BindingContext was used, it will always return the
same CurrencyManager.

Greetings
 
D

Dave Sexton

Hi Bart,

Interesting, thanks.

--
Dave Sexton

Bart Mermuys said:
Hi,

Dave Sexton said:
Hi Bart,

Another workaround for when the DataSource property of the UserControl is
set before it's added to the Form's Controls collection is to bind to a
BindingSource object (in the 2.0 framework).

Yeah that's true, because a BindingSource owns its own CurrencyManager.

CurrencyManager cm =
(CurrencyManager)someBindingContext[someBindingSource];

is the same as:

CurrencyManager cm = someBindingContext.CurrencyManager;

So it doesn't matter what BindingContext was used, it will always return
the same CurrencyManager.

Greetings
 
B

Bart Mermuys

Bart Mermuys said:
Hi,

Dave Sexton said:
Hi Bart,

Another workaround for when the DataSource property of the UserControl is
set before it's added to the Form's Controls collection is to bind to a
BindingSource object (in the 2.0 framework).

Yeah that's true, because a BindingSource owns its own CurrencyManager.

CurrencyManager cm =
(CurrencyManager)someBindingContext[someBindingSource];

is the same as:

CurrencyManager cm = someBindingContext.CurrencyManager;

argh, silly typo, should read:

CurrencyManager cm = someBindingSource.CurrencyManager;
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top