DataBindings.Add

C

C Glenn

This is admitedly vague. But so is my understanding of the problem.
I'm using this chunk of code:

retControl.DataBindings.Add(ctrlBinding.PropertyName,DataSource,BindingField);

This resolves to something like:

Control.DataBindings.Add("Text", SomeDataTable.Rows[1], "Priority");

The only difference that I can see is that one of the DataSets is
created by a DataAdapter through the IDE at design time while the second
is instantiated dynamically at run time. In both cases they contain one
DataTable.

When I attempt to accomplish the same task with the dynamcally
instantiated Control it fails. In the code below you will see a line
that calls the function DeepCloneControl. It never fails within
DeepCloneControl. It always fails after it returns. DeepCloneControl
begins by cloning a control. Then it loops through some of its
properties recreating them in the clone. (Some are excluded.) Finally,
it loops through its bindings recreating them in the clone. (This is
where the problem is. If I comment this loop out, it succeeds.) Only
after the function returns, without ever throwing an exception, does it
fail on the line that called DeepCloneControl. This is the message

Cannot bind to property or column <field name> on DataSource.

Within DeepCloneControl you will notice this:
retControl.DataBindings.Add(ctrlBinding.PropertyName,
DataSource,BindingField);

DataSource refers to an object returned by:
new DataRowCollectionSocket(DataSet.DataTable.Rows);

A DataRowCollectionSocket is defined by:
public interface IDataSocket
{
int Count{get;}
object this[int index]{get;}
}
public class DataRowCollectionSocket: IDataSocket
{
public System.Data.DataRowCollection Data;

public DataRowCollectionSocket(System.Data.DataRowCollection data)
{
this.Data = data;
}

public int Count
{
get
{
return Data.Count;
}
}

public object this[int index]
{
get
{
return Data[index];
}
}
}

Here's the significant bit of code:

tempPanel.Controls.Add(DeepCloneControl(c,i));// This is where it
fails.

public Control DeepCloneControl(Control subject, int i)
{
Type ctrlType = subject.GetType();
ConstructorInfo cInfo = ctrlType.GetConstructor(Type.EmptyTypes);
Control retControl = (Control)cInfo.Invoke(null);

foreach(PropertyInfo pInfo in
ctrlType.GetProperties(BindingFlags.Public|BindingFlags.Instance))
{
if (pInfo.CanWrite && (pInfo.PropertyType.IsValueType ||
pInfo.PropertyType.Name == "String"))
{
try
{
switch(pInfo.Name)
{
case "Parent":
break;
case "SelectionStart":
break;
case "SelectedText":
break;
case "SelectionLength":
break;
default:
pInfo.SetValue(retControl,pInfo.GetValue(subject,null),null);
break;
}
}
catch(Exception ex)
{
Console.WriteLine("Could not assign the value of {0} to
\nObject:\t{1}\nOf Type:\t{2}\nBecause:\t{3}", pInfo.Name,
subject.Name, ctrlType.Name, ex.Message);//Never happens
}
}
}
foreach(Binding ctrlBinding in subject.DataBindings)
{
try
{
string BindingMember = ctrlBinding.BindingMemberInfo.BindingMember;
string BindingField =
BindingMember.Substring(BindingMember.LastIndexOf("."));
retControl.DataBindings.Add(ctrlBinding.PropertyName,
DataSource,BindingField);
}
catch(Exception)
{
MessageBox.Show("Exception thrown at line 139");//Never happens
}
}
return retControl;
}


I know this is a large chunk of code. I apologize for that. Thanks for
any help you may be able to give. I would like to know any and all
reasons why a DataBinding would fail. There has to be a reason for this.
 
D

Dmytro Lapshyn [MVP]

Hi,

What looks suspicious is that you are trying to bind to a DataRow. This is
unusual scenario. Usually one binds to a DataSet or a DataTable (in the
former case, the property name must be specified as TableName.ColumnName),
and an instance of CurrencyManager created behind the scenes will manage the
current row for you.

--
Sincerely,
Dmytro Lapshyn [Visual Developer - Visual C# MVP]


C Glenn said:
This is admitedly vague. But so is my understanding of the problem. I'm
using this chunk of code:

retControl.DataBindings.Add(ctrlBinding.PropertyName,DataSource,BindingField);

This resolves to something like:

Control.DataBindings.Add("Text", SomeDataTable.Rows[1], "Priority");

The only difference that I can see is that one of the DataSets is created
by a DataAdapter through the IDE at design time while the second is
instantiated dynamically at run time. In both cases they contain one
DataTable.

When I attempt to accomplish the same task with the dynamcally
instantiated Control it fails. In the code below you will see a line that
calls the function DeepCloneControl. It never fails within
DeepCloneControl. It always fails after it returns. DeepCloneControl
begins by cloning a control. Then it loops through some of its properties
recreating them in the clone. (Some are excluded.) Finally, it loops
through its bindings recreating them in the clone. (This is where the
problem is. If I comment this loop out, it succeeds.) Only after the
function returns, without ever throwing an exception, does it fail on the
line that called DeepCloneControl. This is the message

Cannot bind to property or column <field name> on DataSource.

Within DeepCloneControl you will notice this:
retControl.DataBindings.Add(ctrlBinding.PropertyName,
DataSource,BindingField);

DataSource refers to an object returned by:
new DataRowCollectionSocket(DataSet.DataTable.Rows);

A DataRowCollectionSocket is defined by:
public interface IDataSocket
{
int Count{get;}
object this[int index]{get;}
}
public class DataRowCollectionSocket: IDataSocket
{
public System.Data.DataRowCollection Data;

public DataRowCollectionSocket(System.Data.DataRowCollection data)
{
this.Data = data;
}

public int Count
{
get
{
return Data.Count;
}
}

public object this[int index]
{
get
{
return Data[index];
}
}
}

Here's the significant bit of code:

tempPanel.Controls.Add(DeepCloneControl(c,i));// This is where it fails.

public Control DeepCloneControl(Control subject, int i)
{
Type ctrlType = subject.GetType();
ConstructorInfo cInfo = ctrlType.GetConstructor(Type.EmptyTypes);
Control retControl = (Control)cInfo.Invoke(null);

foreach(PropertyInfo pInfo in
ctrlType.GetProperties(BindingFlags.Public|BindingFlags.Instance))
{
if (pInfo.CanWrite && (pInfo.PropertyType.IsValueType ||
pInfo.PropertyType.Name == "String"))
{
try
{
switch(pInfo.Name)
{
case "Parent":
break;
case "SelectionStart":
break;
case "SelectedText":
break;
case "SelectionLength":
break;
default:
pInfo.SetValue(retControl,pInfo.GetValue(subject,null),null);
break;
}
}
catch(Exception ex)
{
Console.WriteLine("Could not assign the value of {0} to
\nObject:\t{1}\nOf Type:\t{2}\nBecause:\t{3}", pInfo.Name, subject.Name,
ctrlType.Name, ex.Message);//Never happens
}
}
}
foreach(Binding ctrlBinding in subject.DataBindings)
{
try
{
string BindingMember = ctrlBinding.BindingMemberInfo.BindingMember;
string BindingField =
BindingMember.Substring(BindingMember.LastIndexOf("."));
retControl.DataBindings.Add(ctrlBinding.PropertyName,
DataSource,BindingField);
}
catch(Exception)
{
MessageBox.Show("Exception thrown at line 139");//Never happens
}
}
return retControl;
}


I know this is a large chunk of code. I apologize for that. Thanks for
any help you may be able to give. I would like to know any and all
reasons why a DataBinding would fail. There has to be a reason for this.
 
C

C Glenn

Yes, I know this is a bit odd, but it works for creating a psuedo
continuous form. Each cloned instance of a template panel contains the
same collection of controls and each one of the controls is bound to the
same fields but within a different row in the rows collection.
 

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