Introduction

This is a short demonstration of creating custom button in .NET7 (Core) using a new WPF XAML Designer.

Background

Since Visual Studio 2022 the WPF .NET Framework control extensibility model based on .design.dll and Microsoft.Windows.Design.Extensibility is no longer supported. More about it you can read in New WPF XAML Designer for .NET Framework.

Using the code

This example was made using Visual Studio 2022 and there will be one class library (.NET Framework) project and one WPF Custom Control Library needed:

  1. CustomControlLibrary.WpfCore - WPF Custom Control Library
  2. CustomControlLibrary.WpfCore.DesignTools - please notice that extension .DesignTools is necessary, and that the project is in .NET Framewok 4.8
  3. Rebuild and create package from CustomControlLibrary.WpfCore (right mouse button -> pack).

CustomControlLibrary.WpfCore

  1. Create WPF Custom Control Library and change csproj to look like:
    <Project Sdk="Microsoft.NET.Sdk">
    
        <PropertyGroup>
            <TargetFramework>net7.0-windows</TargetFramework>
            <Nullable>enable</Nullable>
            <UseWPF>true</UseWPF>
        </PropertyGroup>
    
        <ItemGroup>
            <PackageReference Include="NuGet.Build.Packaging" Version="0.2.2">
                <PrivateAssets>all</PrivateAssets>
                <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
            </PackageReference>
        </ItemGroup>
    
        <PropertyGroup>
            <PackageId>CustomControlLibrary.WpfCore</PackageId>
            <Description>Button example</Description>
        </PropertyGroup>
    
        <ItemGroup>
            <PackageFile Include="VisualStudioToolsManifest.xml">
                <Kind>Tools</Kind>
            </PackageFile>
            <PackageFile Include="$(OutputPath)\CustomControlLibrary.WpfCore.DesignTools.dll">
                <Kind>Lib</Kind>
                <TargetPath>Design\CustomControlLibrary.WpfCore.DesignTools.dll</TargetPath>
            </PackageFile>
        </ItemGroup>
    
    </Project>
  2. Rename CustomControl1 to MyButton, also in Generic.xaml.
  3. Add VisualStudioToolsManifest.xml.

MyButton

using System.Windows;
using System.Windows.Controls;

namespace CustomControlLibrary.WpfCore
{
    public class MyButton : Button
    {
        public static DependencyProperty RenderActiveProperty;

        public bool RenderActive
        {
            get { return (bool)GetValue(RenderActiveProperty); }
            set { SetValue(RenderActiveProperty, value); }
        }

        static MyButton()
        {
            RenderActiveProperty = DependencyProperty.Register("RenderActive",
                typeof(bool),
                typeof(MyButton),
                new PropertyMetadata(false));
        }

        public string Test { get; set; }
    }
}

VisualStudioToolsManifest

<FileList>
    <File Reference="CustomControlLibrary.WpfCore.dll">
        <ToolboxItems UIFramework="WPF" VSCategory="CustomControlLibrary.WpfCore" BlendCategory="CustomControlLibrary.WpfCore">
            <Item Type="CustomControlLibrary.WpfCore.MyButton" />
        </ToolboxItems>
    </File>
</FileList>

CustomControlLibrary.WpfCore.DesignTools

  1. Install NuGet package Microsoft.VisualStudio.DesignTools.Extensibility:
    Install-Package Microsoft.VisualStudio.DesignTools.Extensibility -Version 17.4.33103.184
    
  2. Rename Class1 to MyDesignMetadata:
    using Microsoft.VisualStudio.DesignTools.Extensibility.Metadata;
    using System.ComponentModel;
    
    [assembly: ProvideMetadata(typeof(XAMLDesignerExtensibilityCore.DesignTools.MyDesignMetadata))]
    namespace XAMLDesignerExtensibilityCore.DesignTools
    {
        public class MyDesignMetadata : IProvideAttributeTable
        {
            public AttributeTable AttributeTable
            {
                get
                {
                    AttributeTableBuilder builder = new AttributeTableBuilder();
    
                    builder.AddCustomAttributes("CustomControlLibrary.WpfCore.MyButton"
                        , "Test"
                        , new CategoryAttribute("** test **")
                    );
    
                    return builder.CreateTable();
                }
            }
        }
    }
  3. Set build output pat to something like ..\CustomControlLibrary.WpfCore\bin\Debug\net7.0-windows\ or copy it manually to CustomControlLibrary.WpfCore output folder.