Wierd behavior of designer when interrogating DataSet for members

T

Tester

Hi,

I'm developing a component which implements IListSource. The reference code
is attached at the bottom of this post.

When my component is dropped on the form with DataGrid, DataGrid is able to
bind to my component. The problem is if i select my component in designer go
to properties and change Dynamic name to be used in DataSet's Tables that is
returned in GetList(), DataGrid fails to bind to the newly added Table. BUT
the minute i build the project everything is fine again. As you can see from
the attached code I'm not doing anything unusual. It seems that Designer
pre-caches the DataSource. This is unfortunate.

The detailed error when selecting DataGrid's DataMember is:
"Properties Window"
Invalid property value
Cannot create a child list for field "blah...".

Thank you for any assistance on this

Code snippet:

string _tableName;
public string TableName
{
get { return _tableName; }
set { _tableName = value;}
}

#region IListSource Members
public IList GetList()
{
DataSet ds = new DataSet();
ds.Tables.Add(_tableName);
return ((IListSource)ds).GetList();
}
public bool ContainsListCollection
{
get { return true; }
}
#endregion
 
Y

Ying-Shen Yu[MSFT]

Hi,

The type of DataGrid.DataMember is string, so it need save the name of the
datamember.
Maybe we can workaround this problem in this way:
1. In setter of the TableName Property, if it is running in design mode,
then raise the IComponentChangeService.OnComponentChanged event.
2. Deriving from the datagrid, if it is in design mode , then add handler
to the IComponentChangeService.ComponentChanged event, if the tablename
property of the datasource component was changed then change the datamember
value accordingly.
You may find a sample for how to use the IComponentChangeService interface
in its docuementation:
<IComponentChangeService interface>
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/
frlrfSystemComponentModelDesignIComponentChangeServiceClassTopic.asp

Does it resolve your problem?

Best regards,

Ying-Shen Yu [MSFT]
Microsoft Community Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, please remove the word "online"
before sending mail.
 
T

Tester

Raising OnComponentChanged event from TableName property didn't help.
i.e.:
string _tableName;
public string TableName
{
get
{
return _tableName;
}
set
{
if(DesignMode)
{
IComponentChangeService ccs =
(IComponentChangeService)GetService(typeof(IComponentChangeService));
ccs.OnComponentChanged(this,
TypeDescriptor.GetProperties(this)["TableName"], _tableName, value);

}
_tableName = value;
}
}

This seems like a bug that should be reported to WinForms team.
The way I work around the problem is:

string _tableName;
public string TableName
{
get { return _tableName; }
set {_tableName = value;}
}

DataSet ds;

#region IListSource Members
public IList GetList()
{
DataSet dsLocal;
if(DesignMode)
{
if(ds == null)
ds = new DataSet();
ds.Tables.Clear();
}
else
ds = new DataSet();

dsLocal = ds;
dsLocal.Tables.Add(_tableName);
return ((IListSource)dsLocal).GetList();
}
public bool ContainsListCollection
{
get { return true; }
}
#endregion
 
Y

Ying-Shen Yu[MSFT]

Hi,

The code snippet of TableName property seems correct.
How about the event handler in the derived datagrid part?
Here is the code snippet I used in test, you may try it to see if works for
you.

class MyDataGrid : DataGrid
{
private bool firstTime = true;
protected override void OnDataSourceChanged(EventArgs e)
{
//delay the event registration until a
datasource is set.
if (DesignMode && firstTime)
{
IComponentChangeService ccs =
(IComponentChangeService)this.GetService(typeof(IComponentChangeService));
ccs.ComponentChanged +=new
ComponentChangedEventHandler(ccs_ComponentChanged);
firstTime = false;
}
base.OnDataSourceChanged (e);
}
private void ccs_ComponentChanged(object sender, ComponentChangedEventArgs
e)
{
if (null != this.DataSource && e.Component == this.DataSource &&
e.Member.Name == "TableName")
{
this.DataMember = e.NewValue as string;
}
}
}

//In UserControl1 class
#region IListSource Members


DataSet ds = null;
public string TableName
{
get {
if (ds == null)
{
ds = new DataSet();
ds.Tables.Add();
}

return ds.Tables[0].TableName;
}
set {
ds.Tables[0].TableName = value;

if(DesignMode)
{
IComponentChangeService ccs =
(IComponentChangeService)GetService(typeof(IComponentChangeService));
ccs.OnComponentChanged(this,
TypeDescriptor.GetProperties(this)["TableName"],
ds.Tables[0].TableName, value);
}
}
}

public IList GetList()
{
return ((IListSource)ds).GetList();
}

public bool ContainsListCollection
{
get {return true;}
}
#endregion

Since different custom datasources have difference ways to change the name
of their datamembers, It's hard for datagrid designer to determine whether
a change on datasource changed the name of datamember,
in this issue we can check this since we knew the property TableName is
used to modify the name of the datamember. So to my understanding, the
customer datasource component implementer is more proper for implementing
this feature.
Do you think so?
Please feel free to update this thread if you still have questions on this
issue.
Thanks!

Best regards,

Ying-Shen Yu [MSFT]
Microsoft Community Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, please remove the word "online"
before sending mail.
 
T

Tester

Your code works. But I can't really implement DataGrid because I'm writing
component that is not going to be used in controlled environment. The way I
did it seems OK. I always return new DataSet when not in DesignMode and
DataSet that is a member of the class when in DesignMode. It seems that
DataSource is pre-cached somehow. Because if you build the project DataGrid
is able to pick up the new Tables in the DataSource.

Thank you for your help

"Ying-Shen Yu[MSFT]" said:
Hi,

The code snippet of TableName property seems correct.
How about the event handler in the derived datagrid part?
Here is the code snippet I used in test, you may try it to see if works for
you.

class MyDataGrid : DataGrid
{
private bool firstTime = true;
protected override void OnDataSourceChanged(EventArgs e)
{
//delay the event registration until a
datasource is set.
if (DesignMode && firstTime)
{
IComponentChangeService ccs =
(IComponentChangeService)this.GetService(typeof(IComponentChangeService));
ccs.ComponentChanged +=new
ComponentChangedEventHandler(ccs_ComponentChanged);
firstTime = false;
}
base.OnDataSourceChanged (e);
}
private void ccs_ComponentChanged(object sender, ComponentChangedEventArgs
e)
{
if (null != this.DataSource && e.Component == this.DataSource &&
e.Member.Name == "TableName")
{
this.DataMember = e.NewValue as string;
}
}
}

//In UserControl1 class
#region IListSource Members


DataSet ds = null;
public string TableName
{
get {
if (ds == null)
{
ds = new DataSet();
ds.Tables.Add();
}

return ds.Tables[0].TableName;
}
set {
ds.Tables[0].TableName = value;

if(DesignMode)
{
IComponentChangeService ccs =
(IComponentChangeService)GetService(typeof(IComponentChangeService));
ccs.OnComponentChanged(this,
TypeDescriptor.GetProperties(this)["TableName"],
ds.Tables[0].TableName, value);
}
}
}

public IList GetList()
{
return ((IListSource)ds).GetList();
}

public bool ContainsListCollection
{
get {return true;}
}
#endregion

Since different custom datasources have difference ways to change the name
of their datamembers, It's hard for datagrid designer to determine whether
a change on datasource changed the name of datamember,
in this issue we can check this since we knew the property TableName is
used to modify the name of the datamember. So to my understanding, the
customer datasource component implementer is more proper for implementing
this feature.
Do you think so?
Please feel free to update this thread if you still have questions on this
issue.
Thanks!

Best regards,

Ying-Shen Yu [MSFT]
Microsoft Community Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, please remove the word "online"
before sending mail.
 

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