// The parameterless constructor is called by the WPF designer ? public VSXSharpCodeDomProvider(XSharpFileNode fileNode) { _fileNode = fileNode; }
// ========================================================================================= // Constructors // ========================================================================================= /// <summary> /// Initializes a new instance of the <see cref="XSharpNonMemberProperties"/> class. /// </summary> /// <param name="node">The node that contains the properties to expose via the Property Browser.</param> public XSharpNonMemberProperties(XSharpFileNode node) : base(node) { }
// The parameterless constructor is called by the WPF designer ? public VSXSharpCodeDomProvider(XSharpFileNode fileNode) { _fileNode = fileNode; _projectNode = fileNode.ProjectMgr as XSharpProjectNode; }
// Called by the WinForm designer at save time public override void GenerateCodeFromCompileUnit(CodeCompileUnit compileUnit, TextWriter writer, CodeGeneratorOptions options) { // Does that CodeCompileUnit comes from a "Merged" unit ? if (compileUnit.UserData.Contains(XSharpCodeConstants.USERDATA_HASDESIGNER)) { // Retrieve the Form Class CodeTypeDeclaration designerClass = XSharpCodeDomHelper.FindDesignerClass(compileUnit); // and retrieve the filename of the prg file String prgFileName = (string)compileUnit.UserData[XSharpCodeConstants.USERDATA_FILENAME]; // Build the Designer FileName String designerPrgFile = XSharpCodeDomHelper.BuildDesignerFileName(prgFileName); // Retrieve Both CodeCompileUnit CodeCompileUnit formCCU = (CodeCompileUnit)compileUnit.UserData[XSharpCodeConstants.USERDATA_CCU_FORM]; CodeCompileUnit designCCU = (CodeCompileUnit)compileUnit.UserData[XSharpCodeConstants.USERDATA_CCU_DESIGNER]; // suppress generating the "generated code" header in the form.prg formCCU.UserData[XSharpCodeConstants.USERDATA_NOHEADER] = true; // CodeTypeDeclaration formClass = XSharpCodeDomHelper.FindFirstClass(formCCU); CodeTypeDeclaration designClass = XSharpCodeDomHelper.FindFirstClass(designCCU); // Now, remove the members CopyClassProperties(designerClass, formClass); CopyClassProperties(designerClass, designClass); formClass.Members.Clear(); designClass.Members.Clear(); // Now, split the members foreach (CodeTypeMember ctm in designerClass.Members) { // Was it a member that we have found in the original merged CodeCompileUnits ? if (ctm.UserData.Contains(XSharpCodeConstants.USERDATA_FROMDESIGNER)) { if ((bool)ctm.UserData[XSharpCodeConstants.USERDATA_FROMDESIGNER]) { // Comes from the Designer.prg file // so go back to Designer.prg designClass.Members.Add(ctm); } else { // Comes from the original Form file formClass.Members.Add(ctm); } } else { // This must be a member generated by the Designer ! // So we will move Methods to the Form and all others to the Designer if (ctm is CodeMemberMethod) { formClass.Members.Add(ctm); } else { designClass.Members.Add(ctm); } } } // now, we must save both CodeCompileUnit // The received TextWriter is pointing to the Form // so we must create our own TextWriter for the Designer // First, let's make in Memory String generatedSource; MemoryStream inMemory = new MemoryStream(); StreamWriter designerStream = new StreamWriter(inMemory, Encoding.UTF8); // base.GenerateCodeFromCompileUnit(designCCU, designerStream, options); // and force Flush designerStream.Flush(); // Reset and read to String inMemory.Position = 0; StreamReader reader = new StreamReader(inMemory, Encoding.UTF8, true); generatedSource = reader.ReadToEnd(); Encoding realencoding = reader.CurrentEncoding; reader.Close(); designerStream.Close(); XSharpFileNode node = _fileNode.FindChild(designerPrgFile) as XSharpFileNode; bool done = false; if (node != null) { // assign the source to the open buffer when possible if (node.DocumentSetText(generatedSource)) { // then use automation to save the file, because that is much easier // since we do not have to worry about the docdata etc. var oaFile = (OAXSharpFileItem)node.GetAutomationObject(); oaFile.Save(designerPrgFile); done = true; } } if (!done) { // File is not open in editor, so write to disk designerStream = new StreamWriter(designerPrgFile, false, realencoding); designerStream.Write(generatedSource); designerStream.Flush(); designerStream.Close(); NormalizeLineEndings(designerPrgFile); } // The problem here, is that we "may" have some new members, like EvenHandlers, and we need to update their position (line/col) XSharpCodeParser parser = new XSharpCodeParser(_projectNode); parser.TabSize = XSharpCodeDomProvider.TabSize; parser.FileName = designerPrgFile; CodeCompileUnit resultDesigner = parser.Parse(generatedSource); CodeTypeDeclaration resultClass = XSharpCodeDomHelper.FindDesignerClass(resultDesigner); // just to be sure... if (resultClass != null) { // Now push all elements from resultClass to designClass designClass.Members.Clear(); foreach (CodeTypeMember ctm in resultClass.Members) { ctm.UserData[XSharpCodeConstants.USERDATA_FROMDESIGNER] = true; designClass.Members.Add(ctm); } } // Ok,we MUST do the same thing for the Form file base.GenerateCodeFromCompileUnit(formCCU, writer, options); // BUT, the writer is hold by the Form Designer, don't close it !! writer.Flush(); NormalizeLineEndings(prgFileName); // Now, we must re-read it and parse again IServiceProvider provider = (DocDataTextWriter)writer; DocData docData = (DocData)provider.GetService(typeof(DocData)); DocDataTextReader ddtr = new DocDataTextReader(docData); // Retrieve generatedSource = ddtr.ReadToEnd(); // normalize the line endings generatedSource = generatedSource.Replace("\n", ""); generatedSource = generatedSource.Replace("\r", "\r\n"); // Don't forget to set the name of the file where the source is... parser.FileName = prgFileName; resultDesigner = parser.Parse(generatedSource); resultClass = XSharpCodeDomHelper.FindFirstClass(resultDesigner); // just to be sure... if (resultClass != null) { // Now push all elements from resultClass to formClass formClass.Members.Clear(); foreach (CodeTypeMember ctm in resultClass.Members) { ctm.UserData[XSharpCodeConstants.USERDATA_FROMDESIGNER] = false; formClass.Members.Add(ctm); } } // Ok, it should be ok.... // We have updated the file and the types that are stored inside each CCU that have been merged in compileUnit //XSharpCodeDomHelper.MergeCodeCompileUnit(compileUnit, formCCU, designCCU); // And update... designerClass.Members.Clear(); foreach (CodeTypeMember m in designClass.Members) { designerClass.Members.Add(m); } foreach (CodeTypeMember m in formClass.Members) { designerClass.Members.Add(m); } } else { // suppress generating the "generated code" header if (writer is DocDataTextWriter) // Form Editor { compileUnit.UserData[XSharpCodeConstants.USERDATA_NOHEADER] = true; } base.GenerateCodeFromCompileUnit(compileUnit, writer, options); writer.Flush(); // Designer gave us these informations // Now, we must re-read it and parse again if (writer is DocDataTextWriter) { CodeTypeDeclaration formClass = XSharpCodeDomHelper.FindFirstClass(compileUnit); IServiceProvider provider = (DocDataTextWriter)writer; DocData docData = (DocData)provider.GetService(typeof(DocData)); DocDataTextReader ddtr = new DocDataTextReader(docData); // Retrieve string generatedSource = ddtr.ReadToEnd(); XSharpCodeParser parser = new XSharpCodeParser(_projectNode); parser.TabSize = XSharpCodeDomProvider.TabSize; if (compileUnit.UserData.Contains(XSharpCodeConstants.USERDATA_FILENAME)) { parser.FileName = (string)compileUnit.UserData[XSharpCodeConstants.USERDATA_FILENAME]; } CodeCompileUnit resultCcu = parser.Parse(generatedSource); CodeTypeDeclaration resultClass = XSharpCodeDomHelper.FindFirstClass(resultCcu); // just to be sure... if (resultClass != null) { // Now push all elements from resultClass to formClass formClass.Members.Clear(); foreach (CodeTypeMember ctm in resultClass.Members) { formClass.Members.Add(ctm); } } } } }
/// <summary> /// Creates the file node. /// </summary> /// <param name="item">The project element item.</param> /// <returns></returns> public override FileNode CreateFileNode(ProjectElement item) { if (item == null) { throw new ArgumentNullException("item"); } XSharpFileNode node = new XSharpFileNode(this, item); var provider = node.OleServiceProvider; // Use the CreateServices of the Project provider.AddService(typeof(EnvDTE.Project), new OleServiceProvider.ServiceCreatorCallback(this.CreateServices), false); // Use the CreateServices of the Node provider.AddService(typeof(ProjectItem), node.ServiceCreator, false); // Use the CreateServices of the Project provider.AddService(typeof(VSProject), new OleServiceProvider.ServiceCreatorCallback(this.CreateServices), false); //provider.AddService(typeof(VSProject), this.VSProject, false); string include = item.GetMetadata(ProjectFileConstants.Include); if (!string.IsNullOrEmpty(include) && XSharpFileNode.GetFileType(include) == XSharpFileType.XAML) { //Create a DesignerContext for the XAML designer for this file // Use the CreateServices of the Node provider.AddService(typeof(DesignerContext), node.ServiceCreator, false); } if (node.IsFormSubType) { // Use the CreateServices of the Node provider.AddService(typeof(DesignerContext), node.ServiceCreator, false); } if (this.IsCodeFile(include) && item.ItemName == "Compile") provider.AddService(typeof(SVSMDCodeDomProvider), new XSharpVSMDProvider(node), false); return node; }
// Called by the WinForm designer at save time public override void GenerateCodeFromCompileUnit(CodeCompileUnit compileUnit, TextWriter writer, CodeGeneratorOptions options) { // Does that CodeCompileUnit comes from a "Merged" unit ? if (compileUnit is XMergedCodeCompileUnit mergedUnit) { // Retrieve the Form Class CodeTypeDeclaration combinedClass = XSharpCodeDomHelper.FindDesignerClass(compileUnit); // and retrieve the filename of the prg file string prgFileName = mergedUnit.FileName; // Build the Designer FileName // Retrieve Both CodeCompileUnit var formCCU = mergedUnit.FormUnit; var designCCU = mergedUnit.DesignerUnit; string designerPrgFile = designCCU.FileName; var formMembers = new CodeTypeMemberCollection(formCCU.Members); foreach (CodeTypeMember m in formMembers) { m.SetWritten(false); } // suppress generating the "generated code" header in the form.prg formCCU.GenerateHeader = false; CodeTypeDeclaration formClass = formCCU.GetFirstClass(); CodeTypeDeclaration designClass = designCCU.GetFirstClass(); // Now, remove the members CopyClassProperties(combinedClass, formClass); CopyClassProperties(combinedClass, designClass); combinedClass.IsPartial = true; formClass.Members.Clear(); designClass.Members.Clear(); // Now, split the members // And make sure no members are deleted foreach (CodeTypeMember ctm in combinedClass.Members) { // Was it a member that we have found in the original merged CodeCompileUnits ? if (ctm is IXCodeObject xco) { if (ctm.GetFromDesigner()) { // Comes from the Designer.prg file // so go back to Designer.prg designClass.Members.Add(ctm); ctm.SetWritten(true); } else { // Comes from the original Form file formClass.Members.Add(ctm); foreach (CodeTypeMember member in formMembers) { if (member == ctm) { member.SetWritten(true); formMembers.Remove(member); break; } } } } else { // This must be a member generated by the Designer ! // So we will move Methods to the Form and all others to the Designer if (ctm is CodeMemberMethod) { formClass.Members.Add(ctm); ctm.SetWritten(true); } else { designClass.Members.Add(ctm); ctm.SetWritten(true); } } } // Check for members that are not written foreach (CodeTypeMember member in formMembers) { if (!member.WasWritten()) { formClass.Members.Add(member); } } // now, we must save both CodeCompileUnit // The received TextWriter is pointing to the Form // so we must create our own TextWriter for the Designer // First, let's make in Memory String generatedSource; MemoryStream inMemory = new MemoryStream(); StreamWriter designerStream = new StreamWriter(inMemory, Encoding.UTF8); // // Backup original Form file and Form.Designer file // if (XSharpModel.XSettings.FormEditorMakeBackupFiles) { if (File.Exists(prgFileName)) { var bak = Path.ChangeExtension(prgFileName, ".bak"); Utilities.CopyFileSafe(prgFileName, bak); } if (File.Exists(designerPrgFile)) { var bak = Path.ChangeExtension(designerPrgFile, ".bak"); Utilities.CopyFileSafe(designerPrgFile, bak); } } base.GenerateCodeFromCompileUnit(designCCU, designerStream, options); // and force Flush designerStream.Flush(); // Reset and read to String inMemory.Position = 0; StreamReader reader = new StreamReader(inMemory, Encoding.UTF8, true); generatedSource = reader.ReadToEnd(); generatedSource = this._projectNode.SynchronizeKeywordCase(generatedSource, prgFileName); Encoding realencoding = reader.CurrentEncoding; reader.Close(); designerStream.Close(); XSharpFileNode node = _fileNode.FindChild(designerPrgFile) as XSharpFileNode; bool done = false; if (node != null) { // assign the source to the open buffer when possible if (node.DocumentSetText(generatedSource)) { // then use automation to save the file, because that is much easier // since we do not have to worry about the docdata etc. var oaFile = (OAXSharpFileItem)node.GetAutomationObject(); oaFile.Save(designerPrgFile); done = true; } } if (!done) { // File is not open in editor, so write to disk designerStream = new StreamWriter(designerPrgFile, false, realencoding); designerStream.Write(generatedSource); designerStream.Flush(); designerStream.Close(); } // The problem here, is that we "may" have some new members, like EvenHandlers, and we need to update their position (line/col) XSharpCodeParser parser = new XSharpCodeParser(_projectNode, formClass); parser.FileName = designerPrgFile; CodeCompileUnit resultDesigner = parser.Parse(generatedSource); CodeTypeDeclaration resultClass = XSharpCodeDomHelper.FindDesignerClass(resultDesigner); // just to be sure... if (resultClass != null) { // Now push all elements from resultClass to designClass designClass.Members.Clear(); foreach (CodeTypeMember ctm in resultClass.Members) { ctm.SetFromDesigner(true); designClass.Members.Add(ctm); } } // Ok,we MUST do the same thing for the Form file base.GenerateCodeFromCompileUnit(formCCU, writer, options); // BUT, the writer is hold by the Form Designer, don't close it !! writer.Flush(); // Now, we must re-read it and parse again IServiceProvider provider = (DocDataTextWriter)writer; DocData docData = (DocData)provider.GetService(typeof(DocData)); DocDataTextReader ddtr = new DocDataTextReader(docData); // Retrieve generatedSource = ddtr.ReadToEnd(); var newsource = this._projectNode.SynchronizeKeywordCase(generatedSource, prgFileName); if (string.Compare(newsource, generatedSource) != 0) { // get DocDataTextWriter and update the source after the case has been synchronized generatedSource = newsource; DocDataTextWriter dtw = new DocDataTextWriter(docData); dtw.Write(generatedSource); dtw.Flush(); } // Don't forget to set the name of the file where the source is... parser.FileName = prgFileName; resultDesigner = parser.Parse(generatedSource); resultClass = resultDesigner.GetFirstClass(); // just to be sure... if (resultClass != null) { // Now push all elements from resultClass to formClass formClass.Members.Clear(); foreach (CodeTypeMember ctm in resultClass.Members) { ctm.SetFromDesigner(false); formClass.Members.Add(ctm); } } // Ok, it should be ok.... // We have updated the file and the types that are stored inside each CCU that have been merged in compileUnit //XSharpCodeDomHelper.MergeCodeCompileUnit(compileUnit, formCCU, designCCU); // And update... combinedClass.Members.Clear(); combinedClass.Members.AddRange(designClass.Members); combinedClass.Members.AddRange(formClass.Members); } else { var xcompileUnit = ToXCodeCompileUnit(compileUnit); // suppress generating the "generated code" header if (writer is DocDataTextWriter) // Form Editor { compileUnit.SetNoHeader(); } base.GenerateCodeFromCompileUnit(compileUnit, writer, options); writer.Flush(); // Designer gave us these informations // Now, we must re-read it and parse again if (writer is DocDataTextWriter) { CodeTypeDeclaration formClass = compileUnit.GetFirstClass(); IServiceProvider provider = (DocDataTextWriter)writer; DocData docData = (DocData)provider.GetService(typeof(DocData)); DocDataTextReader ddtr = new DocDataTextReader(docData); // Retrieve string generatedSource = ddtr.ReadToEnd(); XSharpCodeParser parser = new XSharpCodeParser(_projectNode); parser.FileName = xcompileUnit.FileName; generatedSource = _projectNode.SynchronizeKeywordCase(generatedSource, parser.FileName); CodeCompileUnit resultCcu = parser.Parse(generatedSource); CodeTypeDeclaration resultClass = resultCcu.GetFirstClass(); // just to be sure... if (resultClass != null) { // Now push all elements from resultClass to formClass formClass.Members.Clear(); foreach (CodeTypeMember ctm in resultClass.Members) { formClass.Members.Add(ctm); } } } } }