DesignerSandbox 0.1.0

dotnet add package DesignerSandbox --version 0.1.0
                    
NuGet\Install-Package DesignerSandbox -Version 0.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="DesignerSandbox" Version="0.1.0">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="DesignerSandbox" Version="0.1.0" />
                    
Directory.Packages.props
<PackageReference Include="DesignerSandbox">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add DesignerSandbox --version 0.1.0
                    
#r "nuget: DesignerSandbox, 0.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package DesignerSandbox@0.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=DesignerSandbox&version=0.1.0
                    
Install as a Cake Addin
#tool nuget:?package=DesignerSandbox&version=0.1.0
                    
Install as a Cake Tool

DesignerSandbox

NuGet Downloads License: MIT

English | 한국어

Edit WPF CustomControl themes as a UserControl in Blend or the Visual Studio XAML designer. At build time they are rewritten back into a ResourceDictionary, so runtime behavior is unchanged.

The problem

A CustomControl's default visuals live in a ResourceDictionary (typically under Themes/Generic.xaml or Themes/Units/*.xaml). The XAML designer in Blend and Visual Studio can only render visual roots — Window, UserControl, Page. A ResourceDictionary has no visual root, so opening a theme file shows an empty canvas. You end up editing styles blind, running the app to see the result.

The fix

Author the theme file as a UserControl instead. The designer renders it WYSIWYG. An MSBuild task hooks BeforeTargets="MarkupCompilePass1", strips the UserControl wrapper, and emits the ResourceDictionary the WPF runtime expects. The compiler never sees the sandbox format.

Install

<ItemGroup>
  <PackageReference Include="DesignerSandbox" Version="0.1.0" PrivateAssets="all" />
</ItemGroup>

<ItemGroup>
  <Page Update="Themes\Units\*.xaml">
    <Sandbox>true</Sandbox>
  </Page>
</ItemGroup>

Requires <UseWPF>true</UseWPF> and an SDK-style csproj (net framework or net 5+).

Authoring

Before — not editable in the designer:


<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:units="clr-namespace:MyApp.UI.Units">
    <Style TargetType="{x:Type units:MyButton}">
        ...
    </Style>
</ResourceDictionary>

After — rendered WYSIWYG in Blend / VS:


<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:units="clr-namespace:MyApp.UI.Units"
             mc:Ignorable="d"
             Background="#202020"
             d:DesignWidth="200" d:DesignHeight="100">

    <UserControl.Resources>
        <Style TargetType="{x:Type units:MyButton}">
            ...
        </Style>
    </UserControl.Resources>

    
    <units:MyButton HorizontalAlignment="Center" VerticalAlignment="Center" />
</UserControl>

Your existing Generic.xaml MergedDictionaries references (<ResourceDictionary Source=".../MyButton.xaml"/>) continue to resolve — the BAML resource URI in the compiled assembly is identical.

How it works

  1. Reads each <Page> item marked with %(Sandbox) == true.
  2. Parses the UserControl, extracts the children of <UserControl.Resources> into a new <ResourceDictionary>.
  3. Drops the design-time body and the d: / mc:Ignorable namespaces; preserves every other xmlns (units:, local:, etc.).
  4. Writes the generated XAML to $(IntermediateOutputPath)DesignerSandbox\ and swaps the <Page> item before MarkupCompilePass1 runs.

The source sandbox file is never consumed by the WPF compiler, so its UserControl root has no runtime cost.

Opt-in, file by file

Only <Page> items with <Sandbox>true</Sandbox> metadata are transformed. Existing ResourceDictionary theme files continue to build unchanged — you can migrate one file at a time.

Configuration

MSBuild property Default Purpose
DesignerSandboxEnabled true Set to false to bypass the transform (useful when diagnosing build issues).
DesignerSandboxIntermediateDir $(IntermediateOutputPath)DesignerSandbox\ Where generated XAML is written.

Limitations

  • Only the root element's <Root.Resources> block is copied. Other root-level markup (e.g. UserControl.Styles) is ignored.
  • ControlTemplate authoring in Blend works for triggers and static visuals; dynamic VisualState requires the standard Blend "Edit Template" workflow.
  • Intermediate BAML is placed under obj/ using the sandbox file's absolute path, which can result in nested obj/obj/... on disk. This is cosmetic — the resource URI inside the compiled assembly is correct.

License

MIT

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.0 108 4/24/2026