- WPF
pack://application:,,,/...URIs do not apply in Uno Platform. Usems-appx:///...or a relative path. - MergedDictionaries lookup order is inverted between WPF and WinUI: in WinUI, merged dictionaries are searched in the reverse order of declaration.
{DynamicResource}is WPF-only. The theme-aware equivalent in WinUI and Uno Platform is{ThemeResource}, which re-evaluates when the active theme changes.- Theme-specific brushes should live under
ResourceDictionary.ThemeDictionarieskeyed byLight,Dark, andHighContrast.
A WPF ResourceDictionary migration is rarely a find-and-replace job. The same XAML concepts carry over to Uno Platform, but the URI syntax, the lookup order inside MergedDictionaries, and the way theme switching resolves at runtime all change. This guide walks through the four concrete shifts before porting a large theme graph.
The Four Things That Change
WPF and WinUI share a core model: a ResourceDictionary is a keyed bag of shareable objects, MergedDictionaries composes external files into the primary dictionary, and resource lookup walks up the visual tree to Application.Resources. What changes is everything at the edges:
| # | What Changes | WPF | WinUI / Uno |
|---|---|---|---|
| 1 | URI scheme for merged files | pack://application:,,,/... | ms-appx:///... or relative path |
| 2 | Lookup order in MergedDictionaries | Last dictionary found sequentially | Checked in reverse of declaration order |
| 3 | Theme-aware markup extension | {DynamicResource} | {ThemeResource} |
| 4 | How theme variants are expressed | Ad-hoc merged files | ThemeDictionaries keyed Light/Dark/HighContrast |
pack:// URIs Are WPF-Only: Use ms-appx:///
In WPF, a merged dictionary typically used a pack URI to point at a compiled resource inside the local assembly or a referenced assembly:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MyApp.Themes;component/Colors.xaml"/>
</ResourceDictionary.MergedDictionaries>WinUI (and therefore Uno Platform on all heads) does not use the pack scheme. The ResourceDictionary.Source property accepts a URI that references a XAML resource within the app package:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
<ResourceDictionary Source="ms-appx:///Themes/Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>Cross-assembly references: WPF's pack://application:,,,/ReferencedAssembly;component/... pattern has no direct one-to-one replacement documented for WinUI's ResourceDictionary.Source. Validate against the target library's documented resource packaging before porting.
MergedDictionaries Lookup Order
This is where WPF muscle memory betrays you.
WPF: The resource that's returned comes from the last dictionary found sequentially in the MergedDictionaries collection. The primary (outer) dictionary still wins over any merged entry with the same key.
WinUI: If multiple merged dictionaries exist, they are checked in the inverse of the order in which they are declared in the MergedDictionaries property. If both Dictionary2.xaml and Dictionary1.xaml declare the same key, the key from Dictionary2.xaml is used first because it is last in the collection.
In practical terms, both frameworks converge on the same outcome for collisions (the later-declared merged file wins), but they describe the algorithm differently and the WinUI rule is explicitly "reverse of declared order." If you relied on WPF's forward-iteration mental model, revisit any code that stitches together a base theme and a per-feature override.
Since Uno Platform 5.0, a ResourceDictionary must be explicitly referenced by a URI to participate in resource resolution. If your WPF team was used to dropping a ResourceDictionary file in the project and assuming it was picked up, that pattern will not work without an explicit merge.
XamlControlsResources ordering: Put XamlControlsResources first in Application.Resources.MergedDictionaries so it doesn't override any other custom styles or resources in your app.
DynamicResource vs. ThemeResource Semantics
WPF's {DynamicResource} defers lookup until the value is actually needed and will re-resolve if the underlying resource is updated. WinUI and Uno Platform do not have a DynamicResource markup extension. The closest equivalent is {ThemeResource}:
| Extension | Framework | Behavior |
|---|---|---|
{StaticResource} | Both | Resolved once at load time |
{DynamicResource} | WPF only | Deferred lookup; re-resolves on dictionary changes |
{ThemeResource} | WinUI / Uno | Resolved at load, re-evaluated on theme changes only |
Narrower semantics: {ThemeResource} re-evaluates specifically on theme changes, not on arbitrary dictionary mutations. If a WPF codebase used DynamicResource to swap resources at runtime outside a theme change, that pattern does not carry over without additional code. Items added to a ResourceDictionary at runtime are not relevant to XAML resource references after the initial parse.
<TextBlock Text="hello world"
Foreground="{ThemeResource FocusVisualWhiteStrokeThemeBrush}"
VerticalAlignment="Center"/>ThemeDictionaries: The Theme Graph, Properly Expressed
In WPF, a theme graph was often assembled by merging different brush files at app startup. In WinUI, the idiomatic pattern is ResourceDictionary.ThemeDictionaries, where each inner ResourceDictionary is keyed with a theme name: Light, Dark, HighContrast, or Default as the fallback.
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<!-- light-theme brushes -->
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<!-- dark-theme brushes -->
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<!-- high-contrast brushes -->
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>Reference the keys with {ThemeResource} from your control templates and styles. Do not use {ThemeResource} inside the theme dictionary itself; use {StaticResource} there, with an exception for theme-agnostic system values like SystemAccentColor.
Lightweight Styling in Uno Platform
WPF teams accustomed to overriding a brush by redeclaring it in App.xaml will find the same mechanism in Uno Platform, with a Uno-specific idiom called lightweight styling. Keys defined later in the lookup chain (Application.Resources or page-level resources) shadow keys from merged control libraries. Uno ships a matched set of theme-resource keys across its Material, Fluent, and Toolkit packages so the overrides compose cleanly.
Migration Checklist
- Replace every
pack://application:,,,/...URI withms-appx:///...or a relative path. - Put
XamlControlsResourcesfirst inApplication.Resources.MergedDictionaries. - Convert
{DynamicResource}references that are theme-related to{ThemeResource}. For non-theme runtime swaps, flag for redesign. - Move per-theme brushes from ad-hoc merged files into
ResourceDictionary.ThemeDictionaries, keyedLight/Dark/HighContrast. - Remember the WinUI lookup order for merged dictionaries: checked in reverse of declaration.
- On Uno Platform 5.0+, every dictionary must be referenced by URI; no ambient pickup.
- If using AI assistance, wire your agent to the Uno Platform MCP servers so its XAML rewrites are grounded against live docs.
FAQ
Will my pack:// URIs compile in Uno Platform?
No. The pack scheme is a WPF URI scheme. Uno Platform / WinUI ResourceDictionary.Source expects ms-appx:/// or a relative path. Expect to rewrite these.
How do I theme-switch at runtime across platforms?
Put the varying brushes under ResourceDictionary.ThemeDictionaries keyed by Light, Dark, and HighContrast, and reference the keys with {ThemeResource}. The platform re-evaluates the lookup when the active theme changes.
What happens to DynamicResource in a templated control?
{DynamicResource} is WPF-only. The Microsoft WPF-to-WinUI 3 pattern guide maps it to {ThemeResource}. Theme-driven re-evaluation works; arbitrary runtime dictionary swaps require redesign.
Do WebAssembly heads load resources differently?
The ms-appx:/// URI scheme is supported by Uno Platform for app-packaged content across all heads. Test your specific theme graph on each target, as head-by-head loading semantics are not explicitly documented in a single reference page.
Organize your Uno ResourceDictionaries with the Markup Resources reference, including ThemeDictionaries and merged dictionary composition in both XAML and C# Markup. See also the field report on the 7 XAML resource keys an AI agent will silently mis-map during migration.
- ResourceDictionary.Source Property (WinUI) →
- Pack URIs in WPF (Microsoft Learn) →
- Merged Resource Dictionaries (WPF) →
- ResourceDictionary and XAML Resource References (WinUI) →
- DynamicResource Markup Extension (WPF) →
- ThemeResource Markup Extension →
- Theme Resources and Theme Dictionaries →
- Guidelines for Custom Theme Resources →
- Migrate WPF App Patterns to WinUI 3 (XAML Features) →
- Uno Platform: Creating Custom Controls →
- Migrating to Uno Platform 5.0 →
- Uno Extensions Markup: Resources →
- Uno Platform MCP Servers →
- Uno Platform for WPF Developers →
Subscribe to Our Blog
Subscribe via RSS
Back to Top