CodeDom Generation Question

M

Mark Olbert

I have a situation where I want to serialize the properties of a custom component. I've played
around with TypeConverters and InstanceDescriptors, but I think I need to go whole hog into the
actual code generation to handle my situation.

Here's what I'm dealing with: I have a component that has a DataSet as one of its fields (which is
exposed as a property of the component). The DataSet is created by the component at designtime based
on selections made by the programmer. The component also has various collections in it which refer
back to that custom dataset. For example, there are objects (that are part of a collection) which
expose the datatype of each database column. They do this by returning the datatype of their
associated DataColumn.

So the component contains objects which must refer to an instance of the custom DataSet. If I were
writing this by hand in c#, it might look something like this:

Component theComponent = new CustomComponent();

// the custom dataset referenced below is constructed by the
// CustomComponent at design time.

theComponent.DataSet = new CustomDataSet();
theComponent.TableList.Add( new TableInfoObject(theComponent.DataSet, <other parameters>);
theComponent.TableList.Add( new TableInfoObject(theComponent.DataSet, <other parameters>);
theComponent.TableList.Add( new TableInfoObject(theComponent.DataSet, <other parameters>);
....

Having to refer to a property of the component seems to make this pattern incompatible with the
InstanceDescriptor approach. On the other hand, the pattern itself looks like it would be reasonably
straightforward to translate into the CodeDom generator system. But if there's an easier way I
wouldn't mind pursuing it :)

Suggestions, leads and thoughts would all be most appreciated!

- Mark
 
Y

Ying-Shen Yu[MSFT]

Hi Mark,

The code serializer is not able to generate code as you wrote.
However, If it is possible derive these classes from Component and create
them using IDesignerHost.CreateComponent, maybe we can generate the code
like below:
private CustomComponent1 customComponent1;
...

//In InitializeComponent method.
customComponent1 = new CustomComponent();
customDataSet1 = new CustomDataSet();

tableInfoObject1 = new TableInfoObject(customDataSet1, <other parameters>);
tableInfoObject2 = new TableInfoObject(customDataSet1, <other parameters>);
tableInfoObject3 = new TableInfoObject(customDataSet1, <other parameters>);

customComponent1.DataSet = customDataSet1;
customComponent1.TableList.Add(tableInfoObject1,

tableInfoObject2,

tableInfoObject3);

Of course, if you want to hide the created component from the Component
tray, you may add the DesignTimeVisible.False attribute to the component
class.
In this way, we may even set the value by properties instead of putting all
of them into the constructor, right?

If my suggestion does not resolve your problem, please feel free to reply
in this thread and let me know more about your problem. I'll follow up with
you in this thread.

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.
 
M

Mark Olbert

Arrggh!!! This CodeDom stuff is infuriating! I just love it when I get these incredibly helpful
error messages like "the designer could not process the code at line 73".

What's worse, the Deserializer() method in my custom CodeDomSerializer class reported no problems
(i.e., I wrapped the base.Deserialize() call in a try/catch block, and there was no exception)...so
the problem appears to be elsewhere than in the Deserializer()???

In any event, here are the lines the designer is having a problem with:

//
// SqlDataPackage custom serialization
//
this.DataSet = new test_ds();
this.TableList.Add(new TableInfo("appeal"));
// the next line blows up
this.TableList[0].Add(new DataField("giver_id", typeof(int)));
this.TableList[0].Add(new DataField("campaign_id", typeof(int)));
this.TableList[0].Add(new DataField("year_id", typeof(int)));

Any suggestions? How the heck do I work around this problem?!?

- Mark
 
M

Mark Olbert

Some more data...

If I manually recast the InitializeComponent() code as the following:

//
// SqlDataPackage custom serialization
//
this.DataSet = new test_ds();
TableInfo junk;
DataField crap;

junk = new TableInfo("appeal");
// the next line throws an error from somewhere in the designtime loading sequence
this.TableList.Add(junk);
crap = new DataField("giver_id", typeof(int));
junk.Add(crap);

junk = new TableInfo("appealxxx");
// the next line throws an error from somewhere in the designtime loading sequence
this.TableList.Add(junk);
crap = new DataField("giver_id", typeof(int));
junk.Add(crap);

I don't get that blasted "the designer can't process" message... but I do get two messages that the
lines where "junk" is Added to this.TableList which say "The variable 'junk' is either undeclared or
was never assigned", which is a real hoot 'cause they're both.

Any other thoughts?

- Mark
 
M

Mark Olbert

Okay, I've gotten the serialization/deserialization process to play nicely with the designer... but
only marginally.

Here's what I ended up doing: I switched the custom CodeDomSerialization class to use array
initialization of the DataFields contained in my TableInfo objects.

To recap, my data structure looks like this:

TableInfoList
TableInfo
DataField
DataField
...
TableInfo
DataField
DataField
...

The TableInfo objects have properties; they're not just Collections. The DataField objects all have
properties too :)

What finally "worked" resulted in InitializeComponent() code that looks like this:

this.TableList.Add(new TableInfo("appeal", new OlbertMcHughLtd.DBFramework.MetaData.DataField[] {
new DataField("giver_id", typeof(int)),
new DataField("campaign_id", typeof(int)),
new DataField("year_id", typeof(int)),
new DataField("user_id", typeof(int)),
new DataField("appeal_date", typeof(System.DateTime)),
new DataField("notes", typeof(string))}));

The problem with this approach is that I don't see any way of setting the properties of the various
TableInfo and DataField objects. Obviously, I could stuff all the values into some big honking ugly
constructor call, but that seems, well, >>ugly<<.

I can't believe that the dotnet environment only understands one initialization "pattern" for
collection classes (i.e., where the items in the collection must be created fully-characterized). I
must be missing something obvious.

Thoughts and hints, anyone?

- Mark
 
Y

Ying-Shen Yu[MSFT]

Hi Mark,

I'd like to confirm if have changed the TableInfo class into a Component
and create it using IDesignerHost.CreateComponent method. Can we generate
the code in this style?
DataSet dataSet1 = new DataSet();
TableInfo info1 = new TableInfo("appeal");
TableInfo info2 = new TableInfo("appeal2");

info1.Add(new DataField("giver_id", typeof(int)));
info1.Add(new DataField("campaign_id", typeof(int)));
info1.Add(new DataField("year_id", typeof(int)));

info2.Add(new DataField("giver_id2", typeof(int)));
info2.Add(new DataField("campaign_id2", typeof(int)));
info2.Add(new DataField("year_id2", typeof(int)));

this.TableList.Add(info1);
this.TableList.Add(info2);

In your second post, I saw you are already trying this approach. I'm not
sure what caused the error message, but I suspect it's related to the
re-use of the variable 'junk' and 'crap'. In design-time the code in
InitializeComponent is not executed but de-serialized, so variable re-use
might cause some problem to the de-serialization mechanism.

Does it work for you after using different variable names?
If you still have problems on this issue, please feel free to reply in this
thread, if this problem can be seperated into a small simple project,
please send me to let me take a look at it. 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.
 
Y

Ying-Shen Yu[MSFT]

Hi Mark,

Define your TableInfo and DataField class as components if you would like
to set properties.....

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.
 
M

Mark Olbert

I have no intention of redesigning this object into a component. The framework ought to be able to
persist, into code, a Collection class without having to jump through hoops!

I am EXTREMELY frustrated right now. What I had working this afternoon is failing for no discernable
reason (see a later post in this thread for details).

- Mark
 
M

Mark Olbert

That is utterly and completely ridiculous!

And I would like to know where it's documented that objects have to be designed as components in
order to be persisted into code...

- Mark
 
M

Mark Olbert

Can anyone suggest why the following property setting code causes my custom CodeDomSerialization
class to be entered:

PropertyDescriptorCollection theProps = TypeDescriptor.GetProperties(thePkg);
if( theProps[theProp] != null )
{
object oldVal = theProps[theProp].GetValue(thePkg);
// this next line activates the CodeDomSerialization object
theProps[theProp].SetValue(thePkg, newVal);
ChangeService.OnComponentChanged(thePkg, theProps[theProp], oldVal, newVal);
}

I realize that, in one sense, this is a stupid question, because, after all, changing a property
value should ultimately cause the code to be re-persisted.

But earlier today that wasn't happening. And I cannot for the life of me remember doing anything to
ths particular section of code that would cause it to stop working.

Put another way, when I have a bunch of properties to set on a component, how do I defer
serialization until after I'm done setting >>all<< of them, as opposed to triggering serialization
after each property change?

- Mark
 
Y

Ying-Shen Yu[MSFT]

Hi mark,

I'd like to give some ideas on this, however after reading your posts
several time,
I'm still not clear why you need defer the code serialization after
setting all the properties?
I guess you are trying to workaround some dependency issue in the
properties of your component. However, I can't see the possible dependency
from the generated code snippet in your previous reply.
<cite>
this.TableList.Add(new TableInfo("appeal", new
OlbertMcHughLtd.DBFramework.MetaData.DataField[] {
new DataField("giver_id", typeof(int)),
new DataField("campaign_id", typeof(int)),
new DataField("year_id", typeof(int)),
new DataField("user_id", typeof(int)),
new DataField("appeal_date", typeof(System.DateTime)),
new DataField("notes", typeof(string))}));
</cite>
Could you make it clear for me?

Thanks for your patience!

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.
 
M

Mark Olbert

Hi,

I think we're losing track of the thread here :). The code snippet you quoted is the one that I said
finally "worked", which is probably why you can't find a problem dependency.

Let me try this a different way.

This CodeDomSerialization-generated code works (I've edited it for brevity):

this.TableList.Add(new TableInfo("appeal", new
OlbertMcHughLtd.DBFramework.MetaData.DataField[] {
new DataField("campaign_id", typeof(int)),
new DataField("notes", typeof(string))}));

But the following kind of pattern causes the designer to fail, even though it compiles correctly:

TableList tempTI = new TableInfo();
tempTI.Name = "appeal";
this.TableList.Add(tempTI);
DataField tempDF = new DataField();
tempDF.Name = "campaign_id";
tempDF.DataType = typeof(int);
tempTI.Add(tempDF);

From this difference in treatment (both compile, but one works and one fails) I'm concluding that
there's some part of the dotnet/VSIDE environment that "looks" for particular kinds of code patterns
to parse when it builds the design-time representation of a component from the souce code contained
in the InitializeComponent() source code.

I'd like to understand what the rules are for generating code that will keep the environment happy,
as it's a little tedious to do things by trial and error :).

Please note that the base CodeDomSerialization.Deserializer() method has no problem with either
approach; it happily chomps away on both. It's some other part of the dotnet/VSIDE environment
that's unhappy.

- Mark
 
Y

Ying-Shen Yu[MSFT]

hi mark,

I have replied you in your another post, if you have any updates to this
problem, please reply to that thread, I'll follow up with you there.
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