DesignerSandbox 0.1.0
dotnet add package DesignerSandbox --version 0.1.0
NuGet\Install-Package DesignerSandbox -Version 0.1.0
<PackageReference Include="DesignerSandbox" Version="0.1.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="DesignerSandbox" Version="0.1.0" />
<PackageReference Include="DesignerSandbox"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add DesignerSandbox --version 0.1.0
#r "nuget: DesignerSandbox, 0.1.0"
#:package DesignerSandbox@0.1.0
#addin nuget:?package=DesignerSandbox&version=0.1.0
#tool nuget:?package=DesignerSandbox&version=0.1.0
DesignerSandbox
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
- Reads each
<Page>item marked with%(Sandbox) == true. - Parses the
UserControl, extracts the children of<UserControl.Resources>into a new<ResourceDictionary>. - Drops the design-time body and the
d:/mc:Ignorablenamespaces; preserves every other xmlns (units:,local:, etc.). - Writes the generated XAML to
$(IntermediateOutputPath)DesignerSandbox\and swaps the<Page>item beforeMarkupCompilePass1runs.
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. ControlTemplateauthoring in Blend works for triggers and static visuals; dynamicVisualStaterequires the standard Blend "Edit Template" workflow.- Intermediate BAML is placed under
obj/using the sandbox file's absolute path, which can result in nestedobj/obj/...on disk. This is cosmetic — the resource URI inside the compiled assembly is correct.
License
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 |