Serializing controls to an external file

by Jose Mojica

I've discovered today that CodeDom classes are serializable. So what does that have to do with anything, right?

When you drop a control into a WinForm and hit the save button, the designer turns the state of your controls into code and puts that code in the form's InitializeComponent method.

To get the code for InitializeComponent, Visual Studio looks at the class being designed (the root component) and asks for its RootDesignerSerializer. This serializer is a class derived from CodeDomSerializer. It has a Serialize method and a Deserialize method. Serialize takes the state of your class and all of its children and converts them into a CodeDom tree. Then the CodeDom tree gets turned into source code and saved with your form. Deserialize takes a CodeDom tree and returns the original object. Deserialize is similar to using reflection. Each statement tells Visual Studio what property to set on each control to make it look as you intended in the designer.

So here's what I did...I wrote my own RootDesignerSerializer. (It's not as complicated as it sounds). It's a class derived from CodeDomSerializer. In its constructor, I create the standard RootDesigner class.

Type rootSerializerType = Type.GetType("System.ComponentModel.Design.Serialization.RootCodeDomSerializer, System.Design, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",true);
_rootSerializer = Activator.CreateInstance(
rootSerializerType,
BindingFlags.CreateInstance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance,
null,
null,
null) as CodeDomSerializer;


Then in the Serialize method, I tell the standard .NET class to Serialize. I get CodeDom back from the Serialize method. Then, because CodeDom is serializable, I save the CodeDom statements to a file.

if (_rootSerializer != null)
serResult = _rootSerializer.Serialize(manager,value);

//serialize all of the code to an external file
FileStream fs = new FileStream("C:\\sercontrol.txt",FileMode.Create);
SoapFormatter formatter = new SoapFormatter();
formatter.Serialize(fs,serResult);
fs.Close();

On the Deserialize, I read the file and give the CodeDom tree to the standard Deserialize function which returns the original object.

if (File.Exists("C:\\sercontrol.txt"))
{
//deserialize the result from a file
FileStream fs = new FileStream("C:\\sercontrol.txt",FileMode.Open);
SoapFormatter formatter = new SoapFormatter();
codeObject = formatter.Deserialize(fs);
fs.Close();
}

if (_rootSerializer != null)
desResult = _rootSerializer.Deserialize(manager,codeObject);

To get VS to use my serializer, I put this attribute on my control:

[RootDesignerSerializerAttribute(typeof(MyRootSerializer),typeof(CodeDomSerializer),true)]


What this means so far is that at design time I can make Visual Studio save the code that would normally go into InitializeComponent to an external file. What I need to do next is make it read this tree at run time and apply it to my form. This will give me the ability to in essense have a code behind file.

More later...

2 Comments

jaini
2005-01-06 23:33:16
need help for codedom
hi Jose Mojica,


I design my own form designer for that i implemented following interfaces
1. IContainer,
2. IDesignerHost,
3. IDesignerLoaderHost,
4. IComponentChangeService,
5. IExtenderProviderService,
6. IDesignerEventService,
7. IExtenderListService,
8. IExtenderProvider,
9. IDesignerSerializationManager,
10.ISite,
11.IDictionaryService,
12.ISelectionService,
13.IEventBindingService,
14.IMenuCommandService,
15.INameCreationService,
16.IResourceService,
17.ISelectionService,
18.IToolboxService,
19.ITypeDescriptorFilterService,
20.ITypeResolutionService,
21.IUIService,
22.IMessageFilter,
23.IResourceReader and
24.IResourceWriter


but when i added image on form and generate and compile the code first time there is no problem
but when i added more some controls on the form and generate and compile the code the following error
message display
The Type or namespace name 'resources' could not be found(are you missing a using directive or an assembly reference?)CS0246 and showing cs file path


I know either i implemented IDesignerSerializationManager or IResourceService one wrong


Thanks in advance


From: jaini

budp
2005-08-16 09:51:38
more complete example of RootCodeDomSerializer
I put the sample code together with Microsoft's CodeDomSerializer sample code and got it to compile.
This required lots of searching for namespaces and dll's.


However, it does not seem to do anything at design or runtime, so it is not being properly invoked, even with the sample designer attributes in place on a derived class.


I am trying to serialize a dynamically created WinForm collection to an external form that can be later deserialized, both at runtime.
This could be c# statements or could be some other form.


The sample code looks like a great basis for what I am trying to do; however, a complete executable example would be very useful.