locked
Populating a NewFile with content from VS add-in RRS feed

  • Question

  • Hi, I would like to be able (from a VS add-in) to create a New unsaved file of type DGML and populate with existing data. In understand that I can use http://msdn.microsoft.com/en-us/library/envdte.itemoperations.newfile.aspx to add the file, but after adding it I would like to replace the empty content with my own. The NewFile method returns a Window object.

    Please mark as answer, if this was it. Visit my SQL Server Compact blog http://erikej.blogspot.com

    Wednesday, December 11, 2013 10:26 AM

Answers

  • From an Add-in, the easiest way to do this would be to simply use the .NET XMLDocument to create and save the file to disk, then add it to your project.

    You're statement "does not really related to a Solution/Project" means this probably isn't 100% applicable. The addin below adds a menu item to the Project context menu, that will in turn add a .DGML file to the selected project.

    using System;
    using System.IO;
    using System.Reflection;
    using System.Xml;
    using Extensibility;
    using EnvDTE;
    using EnvDTE80;
    using Microsoft.VisualStudio.CommandBars;
    
    namespace MyDGMLExperiment
    {
    	public class Connect : IDTExtensibility2
    	{
            private DTE2 applicationObject;
            private AddIn addInInstance;
            private CommandBarButton btnAddDgml;
    
    		public Connect() {}
    
            #region IDTExtensibility2 methods
    
            public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
            {
                applicationObject = (DTE2)application;
                addInInstance = (AddIn)addInInst;
    
                // retrieve the project context menu as a CommandBarPopup
                CommandBar seCmdBar = ((CommandBars)applicationObject.CommandBars)["Context Menus"];
                CommandBarPopup sePopups = (CommandBarPopup)seCmdBar.Controls["Project and Solution Context Menus"];
                CommandBarPopup projPopup = (CommandBarPopup)sePopups.Controls["Project"];
    
                // add a temporary menu item (aka a CommandBarButton)
                btnAddDgml = (CommandBarButton)projPopup.Controls.Add(MsoControlType.msoControlButton, Missing.Value, Missing.Value, 1, true);
                btnAddDgml.Caption = "Add My DGML File";
                btnAddDgml.Click += btnAddDgml_Click;
            }
    
            void btnAddDgml_Click(CommandBarButton Ctrl, ref bool CancelDefault)
            {
                Project targetProj = applicationObject.SelectedItems.Item(1).Project;
                string destPath = Path.GetDirectoryName(targetProj.FullName);
                string fileName = Path.Combine(destPath, "MyDGML.dgml");
    
                // ensure fileName is unique
                int fileNum = 0;
                while (File.Exists(fileName))
                    fileName = Path.Combine(destPath, string.Format("MyDGML{0}.dgml", ++fileNum));
    
                // Create and Save our DGML file to disk
                XmlDocument dgmlDoc = new XmlDocument();
                XmlNode dgNode = dgmlDoc.CreateElement("DirectedGraph");
                XmlAttribute nsAttrib = dgmlDoc.CreateAttribute("xmlns");
                nsAttrib.Value = "http://schemas.microsoft.com/vs/2009/dgml";
                dgNode.Attributes.Append(nsAttrib);
                dgmlDoc.AppendChild(dgNode);
                dgNode.AppendChild(dgmlDoc.CreateElement("Nodes"));
                dgNode.AppendChild(dgmlDoc.CreateElement("Links"));
                dgNode.AppendChild(dgmlDoc.CreateElement("Categories"));
                dgmlDoc.Save(fileName);
    
                // Add the file to the project and save
                targetProj.ProjectItems.AddFromFile(fileName);
                targetProj.Save();
            }
    
            public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom)
            {
                // clean up
                if (btnAddDgml!=null)
                {
                    btnAddDgml.Click -= new _CommandBarButtonEvents_ClickEventHandler(btnAddDgml_Click);
                    btnAddDgml.Delete();
                    btnAddDgml = null;
                }
            }
    
            public void OnAddInsUpdate(ref Array custom) { }
            public void OnStartupComplete(ref Array custom) { }
            public void OnBeginShutdown(ref Array custom) { }
    
            #endregion
    
    	}
    }


    Ed Dore

    Friday, December 13, 2013 9:55 PM
  • The other option would be to ensure the DGML designer is active, then execute a "View.View DGML" command, to display the actual XML, then you could use something like the EnvDTE TextSelection to replace the text. But that would look pretty clunky.

    The nicer, but more difficult scenario would be to implement your own DGML template with a custom IWizard implementation. The template .dgml file would just have a single token (%dgmldata% for example), that you could swap out from the IWizard.RunStarted method.

    But if you've already got an add-in, the easiest scenario would be to just generate the file first, then add it (or open it) after it's been created.

    Sincerely,


    Ed Dore

    • Marked as answer by ErikEJMVP Saturday, December 14, 2013 10:29 AM
    Friday, December 13, 2013 10:00 PM

All replies

  • Hi Erik,

    Please forgive my poor understanding and lack of experience, I cannot get your purposes exactly.

    Do you mean that you want to create the custom file type extension DGML that would be displayed within the Save As dialog box?

    If so, please check the following links:

    Register custom file type with custom UI editor in Visual Studio 2010

    Walkthrough: Adding Features to a Custom Editor

    IVsSaveOptionsDlg Interface

    IVsUIShell::GetSaveFileNameViaDlg Method

    Or, you want to create a template with new file type extension in Visual Studio ?

    If so, please refer to the suggestions in the documents below:

    Creating Extensions By Using the VSIX Project Template

    Creating Visual Studio Templates

    Custom Extension Types with VSIX

    If I had any misunderstanding,please feel free to let me know.

    Sincerely,

    Jane.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Thursday, December 12, 2013 6:51 AM
  • H Jane,

    No, this is not what I mean. DGML is already as supported template type (Directed Graph Document). I can already create a new one by calling the

    NewFile("General\Directed Graph Document");

    What I am asking is: After doing this, can I set the text on the Window to ny own text
    instead of the deafult template text?


    Please mark as answer, if this was it. Visit my SQL Server Compact blog http://erikej.blogspot.com


    • Edited by ErikEJMVP Thursday, December 12, 2013 8:00 AM
    Thursday, December 12, 2013 8:00 AM
  • Will the text be customized based on the context of its invocation, or will you always generate the same content?

    If the text is always the same, I'd opt for building a new template, and use AddFromTemplate. If the content changes/varies based on some other state, you could still use a custom template in conjunction with a custom IWizard implementation.

    The other option would be to insert the text directly using the TextSelection interface as described in the following:

       How to: Control the Code Editor (Visual C#)

    Sincerely,


    Ed Dore

    • Marked as answer by ErikEJMVP Thursday, December 12, 2013 6:13 PM
    • Unmarked as answer by ErikEJMVP Thursday, December 12, 2013 6:52 PM
    Thursday, December 12, 2013 6:05 PM
  • Yes, the text will be context based (I will diagram the schema of a selected database). I think I will investigate inserting text in the template directly, thanks for the link.

    Did some testing with Selection, but am getting Null Ref exception, any suggestions about what I am doing wrong?

                                    EnvDTE.Window window = dte.ItemOperations.NewFile(@"General\Directed Graph Document");
                                    Document doc = window.Document;
                                    MessageBox.Show("Got doc");                               
                                    TextSelection selection = (TextSelection)doc.Selection;
                                    MessageBox.Show("Got selection");
                                    //This does not work
                                    selection.StartOfDocument();
                                    MessageBox.Show("Got selection start");
                                    selection.EndOfDocument(true);
                                    MessageBox.Show("Got selection end");
                                    MessageBox.Show(selection.Text);
                                    selection.InsertFromFile(fileName);
                                    MessageBox.Show("Inserted from file");

    (The DGML editor seems a Little special)


    Please mark as answer, if this was it. Visit my SQL Server Compact blog http://erikej.blogspot.com



    • Edited by ErikEJMVP Thursday, December 12, 2013 6:55 PM
    Thursday, December 12, 2013 6:13 PM
  • Hi Erik,

    I'm guessing you don't have the actual code editor opened here. When you add/open the file, it needs to be opened in the code editor, and not the dgml designer.

    That being said, let me poke around on this and see I can come up with something :-).


    Ed Dore

    Thursday, December 12, 2013 9:12 PM
  • Thanks very much for looking into this, Ed.

    The File/New template is opened in the DGML designer, yes. So the question is - how to switch it to code view.

    I cannot use AddFromTemplate, as the file does not really relate to a solution/project.

    If there is a way to make a window based on a file ignore the file it was based on, that would also work.


    Please mark as answer, if this was it. Visit my SQL Server Compact blog http://erikej.blogspot.com


    • Edited by ErikEJMVP Friday, December 13, 2013 9:36 AM
    Friday, December 13, 2013 8:02 AM
  • From an Add-in, the easiest way to do this would be to simply use the .NET XMLDocument to create and save the file to disk, then add it to your project.

    You're statement "does not really related to a Solution/Project" means this probably isn't 100% applicable. The addin below adds a menu item to the Project context menu, that will in turn add a .DGML file to the selected project.

    using System;
    using System.IO;
    using System.Reflection;
    using System.Xml;
    using Extensibility;
    using EnvDTE;
    using EnvDTE80;
    using Microsoft.VisualStudio.CommandBars;
    
    namespace MyDGMLExperiment
    {
    	public class Connect : IDTExtensibility2
    	{
            private DTE2 applicationObject;
            private AddIn addInInstance;
            private CommandBarButton btnAddDgml;
    
    		public Connect() {}
    
            #region IDTExtensibility2 methods
    
            public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
            {
                applicationObject = (DTE2)application;
                addInInstance = (AddIn)addInInst;
    
                // retrieve the project context menu as a CommandBarPopup
                CommandBar seCmdBar = ((CommandBars)applicationObject.CommandBars)["Context Menus"];
                CommandBarPopup sePopups = (CommandBarPopup)seCmdBar.Controls["Project and Solution Context Menus"];
                CommandBarPopup projPopup = (CommandBarPopup)sePopups.Controls["Project"];
    
                // add a temporary menu item (aka a CommandBarButton)
                btnAddDgml = (CommandBarButton)projPopup.Controls.Add(MsoControlType.msoControlButton, Missing.Value, Missing.Value, 1, true);
                btnAddDgml.Caption = "Add My DGML File";
                btnAddDgml.Click += btnAddDgml_Click;
            }
    
            void btnAddDgml_Click(CommandBarButton Ctrl, ref bool CancelDefault)
            {
                Project targetProj = applicationObject.SelectedItems.Item(1).Project;
                string destPath = Path.GetDirectoryName(targetProj.FullName);
                string fileName = Path.Combine(destPath, "MyDGML.dgml");
    
                // ensure fileName is unique
                int fileNum = 0;
                while (File.Exists(fileName))
                    fileName = Path.Combine(destPath, string.Format("MyDGML{0}.dgml", ++fileNum));
    
                // Create and Save our DGML file to disk
                XmlDocument dgmlDoc = new XmlDocument();
                XmlNode dgNode = dgmlDoc.CreateElement("DirectedGraph");
                XmlAttribute nsAttrib = dgmlDoc.CreateAttribute("xmlns");
                nsAttrib.Value = "http://schemas.microsoft.com/vs/2009/dgml";
                dgNode.Attributes.Append(nsAttrib);
                dgmlDoc.AppendChild(dgNode);
                dgNode.AppendChild(dgmlDoc.CreateElement("Nodes"));
                dgNode.AppendChild(dgmlDoc.CreateElement("Links"));
                dgNode.AppendChild(dgmlDoc.CreateElement("Categories"));
                dgmlDoc.Save(fileName);
    
                // Add the file to the project and save
                targetProj.ProjectItems.AddFromFile(fileName);
                targetProj.Save();
            }
    
            public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom)
            {
                // clean up
                if (btnAddDgml!=null)
                {
                    btnAddDgml.Click -= new _CommandBarButtonEvents_ClickEventHandler(btnAddDgml_Click);
                    btnAddDgml.Delete();
                    btnAddDgml = null;
                }
            }
    
            public void OnAddInsUpdate(ref Array custom) { }
            public void OnStartupComplete(ref Array custom) { }
            public void OnBeginShutdown(ref Array custom) { }
    
            #endregion
    
    	}
    }


    Ed Dore

    Friday, December 13, 2013 9:55 PM
  • The other option would be to ensure the DGML designer is active, then execute a "View.View DGML" command, to display the actual XML, then you could use something like the EnvDTE TextSelection to replace the text. But that would look pretty clunky.

    The nicer, but more difficult scenario would be to implement your own DGML template with a custom IWizard implementation. The template .dgml file would just have a single token (%dgmldata% for example), that you could swap out from the IWizard.RunStarted method.

    But if you've already got an add-in, the easiest scenario would be to just generate the file first, then add it (or open it) after it's been created.

    Sincerely,


    Ed Dore

    • Marked as answer by ErikEJMVP Saturday, December 14, 2013 10:29 AM
    Friday, December 13, 2013 10:00 PM
  • Hi Ed,

    Thanks for all your effort, much appreciated. Currently, I prompt the user for a file location, generate the file and then open it. I think I will just continue to do that.


    Please mark as answer, if this was it. Visit my SQL Server Compact blog http://erikej.blogspot.com

    Saturday, December 14, 2013 10:29 AM