Visual Studio Custom XAML Designer

4.2k Views Asked by At

I have an application where I'm using XAML to represent my own custom object graph. It's quite different from the WPF/Silverlight object model (and not used for UI design), but it is possible to visualize the object graph in a meaningful way. What I'd like to do is add a designer extension to Visual Studio to visualize my specific objects, but I've been having trouble finding information on this topic. Could anybody point me in the right direction?

My main goal is to have some simple visual feedback of the current XAML; I'm not yet at a point where I need the designer to support visual editing. If anybody is curious, it's a tool for simulating industrial machinery; I use XAML to define the machine's components and their connections, but I currently have to run the full simulation to see what the machine looks like.

3

There are 3 best solutions below

2
On BEST ANSWER

You need to create a Visual Studio extension (vsix) that parses the file and visualizes the content. You have two options, a Visual Studio Add-In or a Visual Studio Package (see details of differences in question 1139294). The first one is slightly easier to start with, but the latter will give you more control so I recommend it if you have editing in mind in the future.

Start by downloading SDK for creating Visual Studio extensions, aka Visual Studio 2010 SP1 SDK. For the older non SP1 version click here.

You need to familiarize yourself with creating Visual Studio packages. For a Microsoft tutorial see Walkthrough: Creating a VSPackage. If you follow the tutorial you should have everything needed to trigger a custom component from a menu command. So now all you really need is a e.g. a normal WPF component that can parse/visualize your custom XAML. You also probably need to associate your custom filetype with your component. For this you need a ProvideEditorExtensionAttribute.

There's nothing like a sample, so see The IDE Sample Editor from the samples library. This creates a small file editor custom file types, which is close to what you are asking. Replace the file editor component and the associated file type with your editor and you're almost done!

0
On

Also see the following, http://code.msdn.microsoft.com/windowsdesktop/Designer-View-Over-XML-20a81f17, for a good example of what you want.

0
On

ProvideXmlEditorChooserDesignerViewAttribute is what you're looking for, though it's a bit weird how you have to do it to make it work in this way. https://msdn.microsoft.com/en-us/library/microsoft.visualstudio.modeling.shell.providexmleditorchooserdesignerviewattribute_properties.aspx

I just got this working in my own extension, and it's super easy (once you have the magic formula). Working from the VS Extensibility Sample "Editor with Toolbox" (https://github.com/Microsoft/VSSDK-Extensibility-Samples/tree/master/Editor_With_Toolbox), follow these steps:

  1. Change the custom file extension from .tbx to .xaml. This isn't too difficult, primarily just find+replace .tbx with .xaml and change the tbx.tbx file to xaml.xaml and find+replace in every file in the solution. This marks your EditorFactory as providing an editor for .xaml files.
  2. Open EditorPackage.cs and delete the ProvideEditorExtension and ProvideEditorLogicalView attributes. Replace them with these attributes (obviously replace the stub strings with your actual strings).

    [ProvideXmlEditorChooserDesignerView("UnimportantDesignerViewName", "xaml",
        LogicalViewID.Designer, 10000,
        DesignerLogicalViewEditor = typeof(EditorFactory),
        Namespace = "YourNamespace",
        MatchExtensionAndNamespace = true)]
    [ProvideXmlEditorChooserDesignerView("UnimportantDesignerViewName_Enforced", "xaml",
        LogicalViewID.Designer, 10001,
        DesignerLogicalViewEditor = typeof(EditorFactory))]
    [ProvideEditorLogicalView(typeof(EditorFactory), LogicalViewID.TextView)]
    [ProvideEditorLogicalView(typeof(EditorFactory), LogicalViewID.Code)]
    [ProvideEditorLogicalView(typeof(EditorFactory), LogicalViewID.Designer)]
    [ProvideEditorLogicalView(typeof(EditorFactory), LogicalViewID.Debugging)]
    
  3. Open EditorFactory.cs and edit the CreateEditorInstance method. Here, you'll open the .xaml file specified by the pszMkDocument filepath parameter and verify that it is one of yours (e.g. it uses your schema or something). If so, output your EditorFactory Guids and return S_OK. If not (e.g. if it is a WPF .xaml file), output Guid.Empty and return VS_E_UNSUPPORTEDFORMAT.

    string extension = System.IO.Path.GetExtension(pszMkDocument);
    if (extension.Equals(".xaml", StringComparison.OrdinalIgnoreCase))
    {
        using (System.Xml.XmlReader reader = System.Xml.XmlReader.Create(pszMkDocument))
        {
            reader.MoveToContent();
            if (reader.NodeType == System.Xml.XmlNodeType.Element)
            {
                if (reader.NamespaceURI.Equals("YourNamespace", StringComparison.OrdinalIgnoreCase))
                {
                    EditorPane newEditor = new EditorPane();
                    ppunkDocView = Marshal.GetIUnknownForObject(newEditor);
                    ppunkDocData = Marshal.GetIUnknownForObject(newEditor);
                    pbstrEditorCaption = "";
                    return VSConstants.S_OK;
                }
            }
        }
    }
    return VSConstants.VS_E_UNSUPPORTEDFORMAT;
    

I happened upon this magic attribute formula via the Avalonia GitHub code repository (https://github.com/AvaloniaUI/AvaloniaVS/blob/master/src/AvaloniaVS/Infrastructure/AvaloniaPackage.cs), so thanks so much to those guys for figuring this out. I just implemented this in VS 2017 Community and it works like a charm for me. Good luck to anyone who stumbles upon this trying to accomplish the same arcane task. =)