locked
Using the code editor as a WPF control in VS2010 extensions? RRS feed

  • Question

  • I would like to do the following:

    • Write a VS2010 extension using the VS2010 SDK
    • Create a dialog box in that extension, using WPF
    • Display a bit of C# code generated on the fly in a code editor WPF control in the dialog box

    Is this possible?

    Thanks!

    - Steinar

    Tuesday, September 14, 2010 8:32 AM

All replies

  • "generated on the fly" isn't strictly correct.  It's more like "a complete C# class created from code fragments".

    Tuesday, September 14, 2010 11:11 AM
  • Hi Steinar,

    The 'Editor in a Toolwindow' sample may provide some hints as to how to go about doing this.

    Sincerely,


    Ed Dore
    Thursday, September 16, 2010 3:06 PM
  • Hi Ed,  Thanks.

    I'm wondering about something in the ToolWindow example:

    In MyToolWindow.InitializeEditor() one first gets hold of a ITextBufferFactoryService reference, that sounds like it could be used to create textbuffers.

    But it is not used for this.  Instead a textbuffer is created with a call to IVsEditorAdaptersFactoryService.CreateVsTextBufferAdapter().

    Do you know why this is?  I see that the TextContentType is retrieved from the ITextBufferFactoryService, but that sounds like something that could be handled by a constant...?

    Friday, September 17, 2010 10:42 AM
  • I'm wondering about something in the ToolWindow example:

    In MyToolWindow.InitializeEditor() one first gets hold of a ITextBufferFactoryService reference, that sounds like it could be used to create textbuffers.

    But it is not used for this.  Instead a textbuffer is created with a call to IVsEditorAdaptersFactoryService.CreateVsTextBufferAdapter().

    Do you know why this is? 


    Answering myself here: It's because those two return different kinds of textbuffers. ITextBufferFactoryService creates text buffers of the type ITextBuffer, while IVsEditorAdaptersFactoryService.CreateVsTextBufferAdapter() creates IVsTextBuffer instances.  This is a text buffer that is much closer to the VS unmanaged basics, and not something described in the "Inside the Editor" article.

    Is there a way to create a  IWpfTextViewHost instance that avoids using the IVs* classes and OLE and calls to unmanaged code?

    Monday, September 20, 2010 9:08 AM
  • Hi Steinar,

     

    Thanks for your post.

    Here is a blog explain some detail about embeded editor in tool window, please check:

    http://dotneteers.net/blogs/divedeeper/archive/2010/07/28/LearnVSXNow_2D00_Part45.aspx

    And could you please show me some detail about the "complete C# class created from code fragments", which could help me to display them in the editor.

    Looking forward to your reply.

     

    Best Regards,

    Ziwei Chen

    Monday, September 20, 2010 9:09 AM
  • Hi Victor,

    I'm enclosing a control I've written that has succeeded in displaying a piece of C# code in a WPF window with ShowDialog().  Some points of note:

    • There is no syntax highlighting, even though I've said that the content is C#
    • The scrollbar doesn't show up, even though the text takes more room than the WPF window has available
    • The Source property setter tries to create a new text buffer and display it in the editor.  This does not work.  I have to set the source property before creating the text buffer and editor in the Initialize method

    As for the "complete C# class created from code fragments":

    A C# class has the following string properties:

    • Imports
    • Setup
    • DoIt
    • Teardown

    It's meant to be able to add a plugin for a plugin mechanism, and the "payload" is in "DoIt", you can probably guess at the rest.  The values of the string properties are glued together in a new string that is a complete C# class, befor it is passed to the editor.

    What follows is my UserControl that tries to wrap a VS2010 code editor:

        class CodeEditorUserControlNG : UserControl
        {
            private string source;
            private IOleServiceProvider oleServiceProvider;
            private Guid sourceLanguageId;
            private Microsoft.VisualStudio.ComponentModelHost.IComponentModel componentModel;
            private Microsoft.VisualStudio.Text.ITextBufferFactoryService textBufferFactory;
            private IVsEditorAdaptersFactoryService editorAdaptersFactoryService;
            private IVsTextView textView;

            public CodeEditorUserControlNG()
            {
            }

            public void Initialize(IOleServiceProvider serviceProvider, Guid languageServiceId)
            {
                oleServiceProvider = serviceProvider;
                sourceLanguageId = languageServiceId;
                componentModel = (Microsoft.VisualStudio.ComponentModelHost.IComponentModel)Microsoft.VisualStudio.Shell.Package.GetGlobalService(typeof(Microsoft.VisualStudio.ComponentModelHost.SComponentModel));
                textBufferFactory = componentModel.GetService<Microsoft.VisualStudio.Text.ITextBufferFactoryService>();
                editorAdaptersFactoryService = componentModel.GetService<Microsoft.VisualStudio.Editor.IVsEditorAdaptersFactoryService>();
                IVsTextBuffer bufferAdapter = CreateTextBuffer(Source);
                textView = editorAdaptersFactoryService.CreateVsTextViewAdapter(oleServiceProvider);

                INITVIEW[] _initView = new INITVIEW[] { new INITVIEW() };
                _initView[0].fSelectionMargin = 0;
                _initView[0].fWidgetMargin = 0;
                _initView[0].fVirtualSpace = 0;
                _initView[0].fDragDropMove = 1;
                _initView[0].fVirtualSpace = 0;

                textView.Initialize(bufferAdapter as IVsTextLines, IntPtr.Zero, (uint)TextViewInitFlags.VIF_HSCROLL, _initView);
                IVsUserData data = textView as IVsUserData;
                if (data != null)
                {
                    Guid guid = Microsoft.VisualStudio.Editor.DefGuidList.guidIWpfTextViewHost;
                    object obj;
                    int hr = data.GetData(ref guid, out obj);
                    if ((hr == Microsoft.VisualStudio.VSConstants.S_OK) && obj != null && obj is IWpfTextViewHost)
                    {
                        IWpfTextViewHost textViewHost = obj as IWpfTextViewHost;
                        if (textViewHost != null)
                        {
                            Content = textViewHost.HostControl;
                        }
                    }

                }
            }

            bool HasBeenInitialized()
            {
                if (textBufferFactory != null && editorAdaptersFactoryService != null && textView != null)
                {
                    return true;
                }

                return false;
            }

            private IVsTextBuffer CreateTextBuffer(string mySource)
            {
                IVsTextBuffer bufferAdapter = editorAdaptersFactoryService.CreateVsTextBufferAdapter(oleServiceProvider, textBufferFactory.TextContentType);
                int result = bufferAdapter.InitializeContent(mySource, mySource.Length);
                return bufferAdapter;
            }

            public string Source
            {
                get
                {
                    if (source == null)
                    {
                        return string.Empty;
                    }

                    return source;
                }

                set
                {
                    source = value;
                    if (HasBeenInitialized())
                    {
                        IVsTextBuffer bufferAdapter = CreateTextBuffer(Source);
                        textView.SetBuffer(bufferAdapter as IVsTextLines);
                    }
                }
            }
        }

    • Proposed as answer by Victor_Chen Tuesday, September 21, 2010 7:43 AM
    • Unproposed as answer by Victor_Chen Tuesday, September 21, 2010 7:43 AM
    Monday, September 20, 2010 10:57 AM
  • I thought the reason for not having syntax highlighting might be that I was using textBufferFactory.TextContentType so I tried using the CSharp IContentType instead.  But it didn't make any difference.

    Re: scrollbar, there is a horizontal scrollbar on the bottom of the editor.  But there is no vertical scrollbar.  Though it is possible to scroll the text up and down with the scrollwheel on the mouse.

    Tuesday, September 21, 2010 9:41 AM
  • A simpler version of the control, using only the ComponentModel, and not anything OLE'ish.  Still no syntax highlighting, and also no editing.  But there is one improvement over the OLE'is and IVs*'ish version from the toolwindow example: there is a vertical scrollbar present.

        class CodeEditorUserControlNG2 : UserControl
        {
            private string source;
            private IOleServiceProvider oleServiceProvider;
            private Guid sourceLanguageId;
            private Microsoft.VisualStudio.ComponentModelHost.IComponentModel componentModel;
            private Microsoft.VisualStudio.Text.ITextBufferFactoryService textBufferFactory;
            private Microsoft.VisualStudio.Text.Editor.ITextEditorFactoryService textViewFactory;
            private Microsoft.VisualStudio.Text.Editor.IWpfTextView textView;

            public CodeEditorUserControlNG2()
            {
            }

            public void Initialize(IOleServiceProvider serviceProvider, Guid languageServiceId)
            {
                oleServiceProvider = serviceProvider;
                sourceLanguageId = languageServiceId;
                componentModel = (Microsoft.VisualStudio.ComponentModelHost.IComponentModel)Microsoft.VisualStudio.Shell.Package.GetGlobalService(typeof(Microsoft.VisualStudio.ComponentModelHost.SComponentModel));
                var contentTypeRegistryService = componentModel.GetService<IContentTypeRegistryService>();
                var csharpContentType = contentTypeRegistryService.GetContentType("CSharp");
                textBufferFactory = componentModel.GetService<Microsoft.VisualStudio.Text.ITextBufferFactoryService>();
                textViewFactory = componentModel.GetService<Microsoft.VisualStudio.Text.Editor.ITextEditorFactoryService>();
                Microsoft.VisualStudio.Text.ITextBuffer textBuffer = textBufferFactory.CreateTextBuffer(Source, csharpContentType);
                textView = textViewFactory.CreateTextView(textBuffer);
                IWpfTextViewHost editor = textViewFactory.CreateTextViewHost(textView, true);
                Content = editor.HostControl;
            }

            public string Source
            {
                get
                {
                    if (source == null)
                    {
                        return string.Empty;
                    }

                    return source;
                }

                set
                {
                    source = value;
                }
            }
        }

    Tuesday, September 21, 2010 11:24 AM