This message was discovered on microsoft.public.dotnet.framework.windowsforms.designtime.
| Christian Benien |
Hi there, I have a problem using the Designer/ComponentModel of the ..NET framework. The designer writes all the information relating to the runtime use of a Component into the Components InitializeComponent() function. The design time information goes into a ressource file.
At first I was pretty sure that the Designer is actually calling the InitializeComponent() function to set up all the property values. When you change a property in the code it is reflected in the designer. If you create a new Windows Forms application and add a Button to the Form1 component, the InitializeComponent function is similar to
private void InitializeComponent() { ... this.button1.Text = "button1"; ... }
If you change "button1" to "OK" in the code view, the designer view will show you a button with "OK" on it.
Our project is actually much bigger than this simple Windows Forms example. We have our own implementation of the CodeDomSerializer which generates the content of InitializeComponent(). Yet somewhere there is a limit of what can be put into the function. Let's assume our generated code looks similar to
private void InitializeComponent() { ... string s = "OK"; this.button1.Text = s; ... }
What I would expect from the designer is the execution of InitializeComponent() and setting button1.Text to "OK". This however doesn't work. The Text property of button1 is not set at all, defaulting to an empty string. Code following the statement in question is executed.
This leads to the following conclusion and question:
The InitializeComponent() function is not executed at design time, but instead parsed and interpreted. There are limits on what code is allowed in InitializeComponent(). Does anyone know exactly what those limits are? Or some way around them? Is this a bug or the expected behaviour of the framework?
|
|
|
| |
|
| |
| |
| Frank Hileman |
Hello,
Shawn Burke would be the one to answer your question. Are you delegating the code serialization/deserailzation to the default codedomserializer, and modifying the output? If not, this is what I recommend. Definitely you cannot use flow of control constructs. Any values on the right hand side of a property assignment need to be completely handled with your own serialization/deseralization code if you want the regenerated code to be the same as the input. That is, if you create a typeconverter, and instance descriptors, for something on the right hand side, the serialization/deserialization will work. But if you just do custom code dom serialization, and don't write code to do the deserialization, your custom code will be interpreted, and the results may not be what you want.
If you haven't read it here is the main article:
http://msdn.microsoft.com/library/dndotnet/html/custcodegen.asp
Regards, Frank Hileman Prodige Software Corporation
"Christian Benien" <Click here to reveal e-mail address> wrote in message news:Click here to reveal e-mail address... [Original message clipped]
|
|
|
| |
|
| |
| |
| Christian Benien |
Hello Frank,
thank you for pointing out this article, which I haven't read before. Since I don't think I can solve my problem with TypeDescriptors, I will look into writing my own deserializer. So far I only have a custom CodeDom serializer very similar to the one in Shawn Burke's article. It generates codelines that look like this:
this.MyObject1 = new MyObject(); this.MyObject2 = new MyObject(); .... this.MyObject1.SomeProperty = "whatever"; .... this.MyObject2.AddReference(this.MyObject1.SomeOtherProperty["SomeIdentifier"]);
SomeOtherProperty returns a Hashtable where I look up references to other objects. This works great in runtime code, but cannot be interpreted in design mode.
Christian
|
|
|
| |
|
|
| |
|
| |
| Christian Benien |
While trying to write a custom Deserializer I inserted some debug code into it:
public override object Deserialize(IDesignerSerializationManager manager, object codeObject) { System.IO.StringWriter sw = new System.IO.StringWriter(); Microsoft.CSharp.CSharpCodeProvider cscp = new Microsoft.CSharp.CSharpCodeProvider(); System.CodeDom.Compiler.CodeGeneratorOptions options = new System.CodeDom.Compiler.CodeGeneratorOptions();
System.CodeDom.Compiler.ICodeGenerator debugCode = cscp.CreateGenerator(); if (codeObject is CodeStatement) { CodeStatement statement = codeObject as CodeStatement; debugCode.GenerateCodeFromStatement(codeObject as CodeStatement,sw,options); } else if (codeObject is CodeStatementCollection) foreach (CodeStatement statement in ((CodeStatementCollection)codeObject)) { debugCode.GenerateCodeFromStatement(statement,sw,options); } System.Windows.Forms.MessageBox.Show(sw.ToString());
return GetBaseSerializer(manager).Deserialize(manager, codeObject); }
codeObject contains only the code lines from the base serializer - my custom generated code is not available. How am I supposed to write my own deserializer when I don't get access to the code which I want to deserialize?
Has anyone ever implemented a CodeDomSerialize.Deserialize method? How does it work?
|
|
|
| |
|
| |
| |
| Frank Hileman |
You are generating code in the deserializer, and printing it. No Effect. The code dom is not modified. You need to generate code dom objects in the serialize, and interpret them in the deserialize. The code generator is not what you need -- you only need code-dom objects (unless you need a custom snippet).
Here is another example containing a serailizer:
http://www.gotdotnet.com/team/windowsforms/shapedesigner.aspx
"Christian Benien" <Click here to reveal e-mail address> wrote in message news:Click here to reveal e-mail address... [Original message clipped]
|
|
|
| |
|
| |
| |
| Christian Benien |
I think I've narrowed down my problem to the following:
When I serialize code in the CodeDomSerializer, I can write everything I want to, even stuff not associated with the object which I am currently serializing. Now where does the code go in the deserialization process? It is handled by the CodeDomSerializer associated with the item in the code line. For example I can create a function call like in the third codeline when I am serializing the TextBox. The deserialization is not done by the TextBox deserializer, because DoSomething is part of my RootComponent...
// is handled by the CodeDomSerializer for Button this.button1.Text = "OK";
// is handled by the CodeDomSerializer for TextBox this.textBox1.Text = "Type here";
// who handles this? this.DoSomething();
One would expect that the last line is handled by the CodeDomSerializer that is associated with the Component I'm designing (IDesignerHost.RootComponent). The problem is: the CodeDomSerializer.Serialize method is called for my RootComponent, but the CodeDomSerializer.Deserialize method is NOT called for RootComponent.
Any ideas on this? Or is the deserialization of the RootComponent initialization in InitializeComponent() always done in some class specified by the RootDesignerSerializerAttribute?
|
|
|
| |
|
|
| |
| |
| Shawn Burke [MS] |
this.DoSomething will be invoked on your base type. The Forms designer regularly does this when calling SuspentLayout/ResumeLayout on the base form and it's really no different than accessing any other property or method on the base class.
That line of code will be handled by the default serializer for the component in question -- in this case the RootCodeDomSerializer that Form will get and that derives most of it's functionality from ComponentCodeDomSerializer.
Deserialization is really just interpreting. For each line of code, we build a tree based on the code and then use reflection to apply that code to live objects.
So for "this.TextBox1.Text = "Foo"", we see this, which is the root component. We look for a field called "TextBox1" and get it's value, which is the TextBox. Then we look for a property on that called "Text" and set the value that way. Same for methods.
Hope that helps.
"Christian Benien" <Click here to reveal e-mail address> wrote in message news:Click here to reveal e-mail address... [Original message clipped]
|
|
|
| |
|
| |
|
| |
| Frank Hileman |
I don't have a root component serialization example to try right now. Unless there is some problem with your code, you may be right (need RootDesignerSerializerAttribute). Unfortunately I have not been able to get a complete example of how to write such a serializer. I think the problem is, there is no public class to derive from, which can do most of the work (it is private). So if you do such a serializer you have to rewrite the whole enchilada.
Hello Shawn, can you help here? I cannot.
"Christian Benien" <Click here to reveal e-mail address> wrote in message news:Click here to reveal e-mail address... [Original message clipped]
|
|
|
| |
|
| |
|
|
|
|
|
|
|
|
|