CodeDom Problem -- Would It Kill You Nitwits to Document Stuff?????

M

Mark Olbert

Flame on.

I am SICK and TIRED of the incredibly LOUSY documentation that Microsoft provides for creating
custom components.

Here's my situation:

I've implemented a custom CodeDomSerializer class to handle serialization of my component's state to
and from the InitializeComponent() method.

It was working fine. I could tweak the component's configuration and have the changes persisted to
code, and then when I reopened the project later the changes were deserialized properly. I did this
many, many times, admittedly partially because I thought the process was, well, cool!

But that was yesterday.

Today the deserialization is not taking place (the debugger does not break in the derserialization
method (it did yesterday).

I do not have a custom deserialization method; all I do is call the base class deserialization
method. Yet serialization is working fine -- I've created a fresh new instance of the component,
configured it, and watched it use the custom serializer to persist information to code.

I'm sure there's some simple, but not obvious, reason why what worked yesterday does not work today.

And I'm pretty darn sure, but not absolutely certain, it's something I did.

But what makes me flaming angry mad is IT SHOULD NOT BE POSSIBLE FOR A PROCESS TO WORK ONE DAY AND
FAIL THE NEXT WITHOUT SOME KIND OF ERROR MESSAGE!!!!!!!!

That's just basic good program design. Then again, I've often felt that Microsoft doesn't really
understand good program design. "Ship sh*t and fix it later", as Ballmer's been quoted as saying
(well, I translated what he said publicly, but that was the gist of it). Fortunately for them, and
unfortunately for the rest of us, monopolies can get away with that kind of customer insensitvity.

Flame off.

Now... suggestions on how to diagnose and attack this problem would be much appreicated.

Here's what little I've been able to glean by scattering breakpoints around my code:

When I open a designer for a dervied custom component in a test application, the
InitializeComponent() method of the base custom component runs. Of course, since all the slick
persistence is in the InitializeComponent() method of the derived component class the derived
component is unconfigured.

The OnLoad method of my custom designer runs. I use a UserControl, returned by the GetView()
implementation of the ComponentDocumentDesigner for my component, as the design surface. Yesterday,
the component that the design surface represented was fully initialized by ths point. Today it
isn't.

The InitializeComponent() method of the derived component class runs. After this step, of course,
the derived component has "deserialized" the state information that was persisted in the source code
(although, for some reason, the Deserialize() method of the custom CodeDomSerializer class never
gets entered). Unfortunately, this state information was deserialized too late to initialize the
design surface.

If anyone knows of an example of using a custom design surface for a custom component that I could
study I'd really appreciate it.

And Microsoft... get your act together, and DOCUMENT SOME OF THIS STUFF!!!!!!!!!!!!!!!!!!! You might
even throw in a few examples.

- Mark
 
Y

Ying-Shen Yu[MSFT]

Hi Mark,

Thanks for the information.
I also read your reply to another post, since you have opened a new thread
for this issue, I'll reply to this thread for both threads.

From the description, I think I get some new information about this issue,
to make sure if I have understood your scenario completely, I'd like to
confirm:
1, We are talking about a root designer scenario. The generated code
snippet is in the InitializeComponent method of the root component.

2. If using the default codeDomSerializer for the root component, you can
generate the code for TableInfo property as "this.TableList.Add(new
TableInfo(...))", which works fine.

3.Now you would like to generated the code like initializing a control in
the Form designer(generate a local variable for the TableInfoList, set the
properties, at last add it into the collection. ). You have written a
customized CodeDomSerializer for the root Component. Currently the
Serialize method is working while the Deserialze method never get called.
Did I understand your problem correctly?

First I think I should make clear, when the root designer surface is being
initialized. The method InitializeComponent in the based component class is
*executed by CLR*, so if the code can pass compile, the code will work
(assuming there is no exception thrown while executing the code).
However, the method InitializeComponent in the derived component is
*interpreted* by design-time mechanism based on the CodeStatment
collection,
it's more depending on get the information(e.g. variable name , property
name etc) from the statement and then set value by reflection, so the
deserialization may fail even if the code passed the compilation.

Regarding your current problem, it is still unclear to say where is the
problem, but I think you may try catching the first-chance exception for
CLR exceptions, (check the "Exceptions dialog" in "Debug->Exception" menu),
probably there is an internal exception before the Deserialize method get
called. If you did catch an internal exception, the exception message/type
and stack trace might be helpful to track down the problem.

In addition, Consider makeing the class deriving from Component is a bit
intrusive, then is it possible to implement IComponent interface on your
TableInfo component?
Then you may add the TableInfo component to the designer container and add
into the TableInfo collection, the serialized code will look like adding a
control in a Form.
Do you think that code style is acceptable?

If you have any updates on this issue, please be free to post
I'll follow up with you on this topic.

Have a nice Day!

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

Ying-Shen,

(my apologies if in my ignorance I've blown a cultural protocol and just called you by your last
name) I've replied to your questions/comments below. I also put an update at the end.
1, We are talking about a root designer scenario. The generated code
snippet is in the InitializeComponent method of the root component.
Correct.

2. If using the default codeDomSerializer for the root component, you can
generate the code for TableInfo property as "this.TableList.Add(new
TableInfo(...))", which works fine.

Yes, that pattern is the one that works. The custom CodeDomSerializer class is for the custom
component class, however, not the root designer (it gets triggered when the root designer --
actually, the custom design surface for the root designer -- does an OnComponentChanged() call for
the instance of the component being designed.
3.Now you would like to generated the code like initializing a control in
the Form designer(generate a local variable for the TableInfoList, set the
properties, at last add it into the collection. ). You have written a
customized CodeDomSerializer for the root Component. Currently the
Serialize method is working while the Deserialze method never get called.
Did I understand your problem correctly?

Actually, I need to generate code when the user modifies the custom component's design surface. I
create derived instances of my custom component, instances of which are then embedded in forms. The
pattern is similar, I think, to how custom datasets are used -- create a custom dataset class using,
say, the dataset design surface, and then add an instance of the custom dataset to a particular
form.

Yes, the Deserialize method never gets called when the custom design surface opens. Interestingly,
it >>does<< get called when you load a form that contains an instance of the custom component on it.
But whatever is processing the InitializeComponent() code for the custom design surface, it doesn't
appear to be the Deserialize method.
First I think I should make clear, when the root designer surface is being
initialized. The method InitializeComponent in the based component class is
*executed by CLR*, so if the code can pass compile, the code will work
(assuming there is no exception thrown while executing the code).
However, the method InitializeComponent in the derived component is
*interpreted* by design-time mechanism based on the CodeStatment
collection,
it's more depending on get the information(e.g. variable name , property
name etc) from the statement and then set value by reflection, so the
deserialization may fail even if the code passed the compilation.

Regarding your current problem, it is still unclear to say where is the
problem, but I think you may try catching the first-chance exception for
CLR exceptions, (check the "Exceptions dialog" in "Debug->Exception" menu),
probably there is an internal exception before the Deserialize method get
called. If you did catch an internal exception, the exception message/type
and stack trace might be helpful to track down the problem.

Great idea! I should've tried that earlier. Thanx!
In addition, Consider makeing the class deriving from Component is a bit
intrusive, then is it possible to implement IComponent interface on your
TableInfo component?
Then you may add the TableInfo component to the designer container and add
into the TableInfo collection, the serialized code will look like adding a
control in a Form.
Do you think that code style is acceptable?

I could try that, but seeing as right now I've gotten it to work I need to move on with the rest of
my project.

I think it would be really, really helpful if there was a documentation resource that spelled out
things like when one should/needs to make a class a component rather than a "regular" class.

Update:

I worked around the problem of the custom component class not being initialized "early" enough in
design mode by adding an event to the custom control that is raised when the EndInit() method of the
ISupportInitialize interface runs. That solves the problem... but I'm still left wondering why in
the heck things were working earlier and suddenly stopped. It's not as if I could've taken out a
bunch of event raising and event handling code without noticing :)!

- Mark
 

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