RootCodeDomSerializer.cs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. //
  2. // System.ComponentModel.Design.Serialization.RootCodeDomSerializer
  3. //
  4. // Authors:
  5. // Ivan N. Zlatev (contact i-nZ.net)
  6. //
  7. // (C) 2007 Ivan N. Zlatev
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining
  10. // a copy of this software and associated documentation files (the
  11. // "Software"), to deal in the Software without restriction, including
  12. // without limitation the rights to use, copy, modify, merge, publish,
  13. // distribute, sublicense, and/or sell copies of the Software, and to
  14. // permit persons to whom the Software is furnished to do so, subject to
  15. // the following conditions:
  16. //
  17. // The above copyright notice and this permission notice shall be
  18. // included in all copies or substantial portions of the Software.
  19. //
  20. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27. //
  28. #if NET_2_0
  29. using System;
  30. using System.Collections;
  31. using System.Collections.Generic;
  32. using System.ComponentModel;
  33. using System.ComponentModel.Design;
  34. using System.CodeDom;
  35. namespace System.ComponentModel.Design.Serialization
  36. {
  37. internal class RootCodeDomSerializer : CodeDomSerializer
  38. {
  39. internal class CodeMap
  40. {
  41. private string _className;
  42. private Type _classType;
  43. private List<CodeMemberField> _fields;
  44. private CodeStatementCollection _preInit;
  45. private CodeStatementCollection _init;
  46. private CodeStatementCollection _postInit;
  47. public CodeMap (Type classType, string className)
  48. {
  49. if (classType == null)
  50. throw new ArgumentNullException ("classType");
  51. if (className == null)
  52. throw new ArgumentNullException ("className");
  53. _classType = classType;
  54. _className = className;
  55. _fields = new List<CodeMemberField> ();
  56. _preInit = new CodeStatementCollection ();
  57. _init = new CodeStatementCollection ();
  58. _init = new CodeStatementCollection ();
  59. _postInit = new CodeStatementCollection ();
  60. }
  61. public void AddField (CodeMemberField field)
  62. {
  63. _fields.Add (field);
  64. }
  65. public void AddPreInitStatement (CodeStatement statement)
  66. {
  67. _preInit.Add (statement);
  68. }
  69. public void AddInitStatement (CodeStatement statement)
  70. {
  71. _init.Add (statement);
  72. }
  73. public void AddInitStatements (CodeStatementCollection statements)
  74. {
  75. _init.AddRange (statements);
  76. }
  77. public void AddPostInitStatement (CodeStatement statement)
  78. {
  79. _postInit.Add (statement);
  80. }
  81. /*
  82. class Type : BaseType
  83. {
  84. #region Windows Form Designer generated code
  85. private void InitializeComponent ()
  86. {
  87. preInit;
  88. init;
  89. postInit;
  90. }
  91. private field1;
  92. private field2;
  93. #endregion
  94. }
  95. */
  96. public CodeTypeDeclaration GenerateClass ()
  97. {
  98. CodeTypeDeclaration clas = new CodeTypeDeclaration (_className);
  99. clas.BaseTypes.Add (_classType);
  100. clas.StartDirectives.Add (new CodeRegionDirective (CodeRegionMode.Start, "Windows Form Designer generated code"));
  101. CodeMemberMethod initialize = new CodeMemberMethod ();
  102. initialize.Name = "InitializeComponent";
  103. initialize.ReturnType = new CodeTypeReference (typeof (void));
  104. initialize.Attributes = MemberAttributes.Private;
  105. initialize.Statements.AddRange (_preInit);
  106. initialize.Statements.AddRange (_init);
  107. initialize.Statements.AddRange (_postInit);
  108. clas.Members.Add (initialize);
  109. foreach (CodeMemberField field in _fields)
  110. clas.Members.Add (field);
  111. clas.EndDirectives.Add (new CodeRegionDirective (CodeRegionMode.End, null));
  112. return clas;
  113. }
  114. public void Clear ()
  115. {
  116. _preInit.Clear ();
  117. _init.Clear ();
  118. _postInit.Clear ();
  119. _fields.Clear ();
  120. }
  121. }
  122. private CodeMap _codeMap;
  123. public RootCodeDomSerializer ()
  124. {
  125. }
  126. public override object Serialize (IDesignerSerializationManager manager, object value)
  127. {
  128. if (manager == null)
  129. throw new ArgumentNullException ("manager");
  130. if (value == null)
  131. throw new ArgumentNullException ("value");
  132. if (_codeMap == null)
  133. _codeMap = new CodeMap (value.GetType (), manager.GetName (value));
  134. _codeMap.Clear ();
  135. RootContext rootContext = new RootContext (new CodeThisReferenceExpression (), value);
  136. manager.Context.Push (rootContext);
  137. this.SerializeComponents (manager, ((IComponent) value).Site.Container.Components, (IComponent) value);
  138. // Serialize root component
  139. //
  140. CodeStatementCollection statements = new CodeStatementCollection ();
  141. statements.Add (new CodeCommentStatement (String.Empty));
  142. statements.Add (new CodeCommentStatement (manager.GetName (value)));
  143. statements.Add (new CodeCommentStatement (String.Empty));
  144. // Note that during the serialization process below ComponentCodeDomSerializer
  145. // will be invoked to serialize the rootcomponent during expression serialization.
  146. // It will check for RootContext and return that.
  147. base.SerializeProperties (manager, statements, value, new Attribute[0]);
  148. base.SerializeEvents (manager, statements, value, new Attribute[0]);
  149. _codeMap.AddInitStatements (statements);
  150. manager.Context.Pop ();
  151. return _codeMap.GenerateClass ();
  152. }
  153. private void SerializeComponents (IDesignerSerializationManager manager, ICollection components, IComponent rootComponent)
  154. {
  155. foreach (IComponent component in components) {
  156. if (!Object.ReferenceEquals (component, rootComponent)) {
  157. manager.Context.Push (new ExpressionContext (null, null, rootComponent, component));
  158. SerializeComponent (manager, component);
  159. manager.Context.Pop ();
  160. }
  161. }
  162. }
  163. private void SerializeComponent (IDesignerSerializationManager manager, IComponent component)
  164. {
  165. CodeDomSerializer serializer = base.GetSerializer (manager, component) as CodeDomSerializer; // ComponentCodeDomSerializer
  166. if (serializer != null) {
  167. this.Code.AddField (new CodeMemberField (component.GetType (), manager.GetName (component)));
  168. CodeStatementCollection statements = (CodeStatementCollection) serializer.Serialize (manager, component);
  169. CodeStatement ctorStatement = ExtractCtorStatement (manager, statements, component);
  170. if (ctorStatement != null)
  171. Code.AddPreInitStatement (ctorStatement);
  172. Code.AddInitStatements (statements);
  173. }
  174. }
  175. internal CodeMap Code {
  176. get { return _codeMap; }
  177. }
  178. // Used to remove the ctor from the statement colletion in order for the ctor statement to be moved.
  179. //
  180. private CodeStatement ExtractCtorStatement (IDesignerSerializationManager manager, CodeStatementCollection statements,
  181. object component)
  182. {
  183. CodeStatement result = null;
  184. CodeAssignStatement assignment = null;
  185. CodeObjectCreateExpression ctor = null;
  186. int toRemove = -1;
  187. for (int i=0; i < statements.Count; i++) {
  188. assignment = statements[i] as CodeAssignStatement;
  189. if (assignment != null) {
  190. ctor = assignment.Right as CodeObjectCreateExpression;
  191. if (ctor != null && manager.GetType (ctor.CreateType.BaseType) == component.GetType ()) {
  192. result = assignment;
  193. toRemove = i;
  194. }
  195. }
  196. }
  197. if (toRemove != -1)
  198. statements.RemoveAt (toRemove);
  199. return result;
  200. }
  201. public override object Deserialize (IDesignerSerializationManager manager, object codeObject)
  202. {
  203. CodeTypeDeclaration declaration = (CodeTypeDeclaration) codeObject;
  204. Type rootType = manager.GetType (declaration.BaseTypes[0].BaseType);
  205. object root = manager.CreateInstance (rootType, null, declaration.Name, true);
  206. RootContext rootContext = new RootContext (new CodeThisReferenceExpression (), root);
  207. manager.Context.Push (rootContext);
  208. CodeMemberMethod initComponentMethod = GetInitializeMethod (declaration);
  209. if (initComponentMethod == null)
  210. throw new InvalidOperationException ("InitializeComponent method is missing in: " + declaration.Name);
  211. foreach (CodeStatement statement in initComponentMethod.Statements)
  212. base.DeserializeStatement (manager, statement);
  213. manager.Context.Pop ();
  214. return root;
  215. }
  216. private CodeMemberMethod GetInitializeMethod (CodeTypeDeclaration declaration)
  217. {
  218. CodeMemberMethod method = null;
  219. foreach (CodeTypeMember member in declaration.Members) {
  220. method = member as CodeMemberMethod;
  221. if (method != null && method.Name == "InitializeComponent")
  222. break;
  223. }
  224. return method;
  225. }
  226. }
  227. }
  228. #endif