From dotnet-skills
Migrating desktop apps. WPF/WinForms to .NET 8+, WPF to WinUI or Uno, UWP to WinUI, decision matrix.
npx claudepluginhub wshaddix/dotnet-skillsThis skill uses the workspace's default tool permissions.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
Context-dependent migration guidance for Windows desktop applications. Covers WPF .NET Framework to .NET 8+, WPF to WinUI 3 (Windows-only modernization), WPF to Uno Platform (cross-platform), WinForms .NET Framework to .NET 8+, UWP to WinUI 3, UWP to Uno Platform (cross-ref), and a decision matrix for choosing the right migration target based on project constraints.
Version assumptions: .NET 8.0+ baseline (current LTS). dotnet-upgrade-assistant for automated migration. .NET 9 features explicitly marked where applicable.
Scope boundary: This skill owns migration paths between desktop frameworks and from .NET Framework to modern .NET. Individual framework patterns (WPF modern, WinUI, WinForms modern) are owned by the respective framework skills. The framework selection decision tree is owned by [skill:dotnet-ui-chooser].
Out of scope: WPF .NET 8+ development patterns -- see [skill:dotnet-wpf-modern]. WinUI 3 development patterns -- see [skill:dotnet-winui]. WinForms .NET 8+ development patterns -- see [skill:dotnet-winforms-basics]. Uno Platform development patterns -- see [skill:dotnet-uno-platform]. Framework selection decision tree -- see [skill:dotnet-ui-chooser]. Desktop testing -- see [skill:dotnet-ui-testing-core].
Cross-references: [skill:dotnet-wpf-modern] for WPF .NET 8+ patterns, [skill:dotnet-winui] for WinUI 3 patterns, [skill:dotnet-winforms-basics] for WinForms .NET 8+ patterns, [skill:dotnet-uno-platform] for Uno Platform patterns, [skill:dotnet-ui-chooser] for framework selection, [skill:dotnet-ui-testing-core] for desktop testing.
Choose a migration path based on your current framework and target goals. Each path has different trade-offs in effort, risk, and capability gain.
| Current | Target | Effort | Risk | When to Choose |
|---|---|---|---|---|
| WPF .NET Framework | WPF .NET 8+ | Low-Medium | Low | Modernize runtime, keep existing UI |
| WPF .NET Framework | WinUI 3 | High | Medium | Modern Windows UI, touch/pen, Fluent |
| WPF .NET Framework | Uno Platform | High | Medium-High | Cross-platform needed |
| WinForms .NET Framework | WinForms .NET 8+ | Low | Low | Modernize runtime, keep existing UI |
| UWP | WinUI 3 | Medium | Medium | Stay Windows-only, modern runtime |
| UWP | Uno Platform | Medium-High | Medium | Cross-platform needed from UWP |
The lowest-risk migration path. Keeps your existing XAML and code-behind intact while moving to modern .NET with better performance, DI support, and side-by-side deployment.
The .NET Upgrade Assistant automates the bulk of the migration:
# Install the upgrade assistant
dotnet tool install -g upgrade-assistant
# Analyze the project first (non-destructive)
upgrade-assistant analyze MyWpfApp.sln
# Upgrade the project
upgrade-assistant upgrade MyWpfApp.sln
What the upgrade assistant handles:
.csproj conversion from legacy format to SDK-stylepackages.config to PackageReference migrationnet8.0-windowsAssemblyInfo.cs properties moved to .csprojWhat requires manual work:
App.config settings migration to appsettings.json or Host builder configurationSettings.settings / My.Settings (VB.NET) migrationCoreWCF or migrate to gRPC/REST)System.Runtime.InteropServices)Most WPF APIs are identical between .NET Framework and .NET 8+. Key differences:
| Area | .NET Framework | .NET 8+ | Action |
|---|---|---|---|
| Clipboard | Clipboard.SetText() | Same API | No change |
| Printing | PrintDialog, PrintVisual | Same API | No change |
| BitmapEffect | Deprecated (software-rendered) | Removed | Use Effect / ShaderEffect |
DrawingContext.PushEffect | Available | Removed | Use ShaderEffect |
| XPS documents | System.Windows.Xps | Requires NuGet package | Add System.Windows.Xps PackageReference |
| Speech synthesis | System.Speech | Requires NuGet package | Add System.Speech PackageReference |
After migration, update NuGet packages to .NET 8-compatible versions:
# List outdated packages
dotnet list package --outdated
# Update packages (one at a time for safer migration)
dotnet add package Newtonsoft.Json --version 13.*
dotnet add package MaterialDesignThemes --version 5.*
Common package replacements:
Unity container -> Microsoft.Extensions.DependencyInjection (built-in)Autofac -> update to latest (supports .NET 8)log4net / NLog -> consider Microsoft.Extensions.Logging with Serilog or NLog providerEntityFramework (EF6) -> Microsoft.EntityFrameworkCore 8.xPerMonitorV2 DPI awareness by default (not SystemAware like .NET Framework).<Nullable>disable</Nullable> initially, then fix incrementally.using statements. Disable with <ImplicitUsings>disable</ImplicitUsings> if needed.AssemblyLoadContext replaces AppDomain for assembly isolation. Plugin architectures using AppDomain.CreateDomain need rework.For post-migration WPF patterns (Host builder, MVVM Toolkit, modern C#), see [skill:dotnet-wpf-modern].
Migrate when you need modern Windows-native UI: Fluent Design, touch/pen input, Windows 11 integration (widgets, Mica), or UWP-style APIs on modern .NET. This is a partial rewrite -- XAML concepts transfer but APIs and namespaces differ.
ThemeMode = ThemeMode.System| WPF XAML | WinUI 3 XAML | Notes |
|---|---|---|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | Same URI (but resolves to Microsoft.UI.Xaml types, not System.Windows) | No xmlns change, but runtime types differ |
{Binding Path=Name} | {x:Bind Name, Mode=OneWay} | Prefer x:Bind (compiled, type-safe) |
DataContext binding | Code-behind property + x:Bind | x:Bind resolves against code-behind |
Window inherits from System.Windows.Window | Window inherits from Microsoft.UI.Xaml.Window | Different base class and API |
UserControl | UserControl (Microsoft.UI.Xaml namespace) | Same concept, different namespace |
Style with TargetType | Same | Works the same way |
DataTemplate | Needs x:DataType for x:Bind | Required for compiled bindings |
ContextMenu | MenuFlyout | Different control type |
StatusBar | No built-in equivalent | Use custom CommandBar or InfoBar |
RibbonControl | No built-in equivalent | Use NavigationView + CommandBar |
{Binding} to {x:Bind} for compile-time safetyFor WinUI 3 patterns and project setup, see [skill:dotnet-winui].
Migrate when you need cross-platform reach from a WPF codebase. Uno Platform uses the WinUI XAML API surface, so WPF XAML skills transfer partially, but the migration involves adapting to WinUI XAML patterns.
The migration from WPF to Uno Platform is similar to WPF to WinUI 3 (since Uno uses the WinUI API surface), with additional cross-platform considerations:
Uno Extensions provides cross-platform replacements for common WPF patterns:
| WPF Pattern | Uno Extensions Replacement |
|---|---|
| Custom navigation | Uno.Extensions.Navigation |
| Manual DI setup | Uno.Extensions.DependencyInjection (wraps MS DI) |
appsettings.json config | Uno.Extensions.Configuration |
| Manual HTTP clients | Uno.Extensions.Http (typed clients with Refit) |
| Manual serialization | Uno.Extensions.Serialization |
For Uno Platform development patterns, see [skill:dotnet-uno-platform]. For per-target deployment guidance, see [skill:dotnet-uno-targets].
Similar to WPF migration but typically simpler due to WinForms' less complex project structure.
# Analyze first
upgrade-assistant analyze MyWinFormsApp.sln
# Upgrade
upgrade-assistant upgrade MyWinFormsApp.sln
What the upgrade assistant handles:
.csproj conversion to SDK-style with <UseWindowsForms>true</UseWindowsForms>net8.0-windowspackages.config to PackageReferenceAssemblyInfo.cs migration to project propertiesWhat requires manual work:
App.config / Settings.settings migrationMy.Settings (VB.NET) migration to modern configurationWinForms designer files (.Designer.cs) generally migrate cleanly. The Visual Studio WinForms designer for .NET 8+ is fully supported.
Known designer issues:
<ForceDesignerDPIUnaware>true</ForceDesignerDPIUnaware>)After migrating to .NET 8+, consider adopting modern patterns incrementally:
PerMonitorV2 modeFor WinForms .NET 8+ patterns, see [skill:dotnet-winforms-basics].
UWP's natural migration target. WinUI 3 uses the same XAML API surface with namespace changes.
The primary migration task is updating namespaces from Windows.UI.* to Microsoft.UI.*:
| UWP Namespace | WinUI 3 Namespace |
|---|---|
Windows.UI.Xaml | Microsoft.UI.Xaml |
Windows.UI.Xaml.Controls | Microsoft.UI.Xaml.Controls |
Windows.UI.Xaml.Media | Microsoft.UI.Xaml.Media |
Windows.UI.Composition | Microsoft.UI.Composition |
Windows.UI.Text | Microsoft.UI.Text |
Keep as-is: Windows.Storage, Windows.Networking, Windows.Security, Windows.ApplicationModel, Windows.Devices -- these WinRT APIs remain unchanged.
| Concern | UWP | WinUI 3 |
|---|---|---|
| App lifecycle | CoreApplication + suspension | Windows App SDK AppInstance |
| Window management | Window.Current (singleton) | Track window references manually |
| Dispatcher | CoreDispatcher.RunAsync | DispatcherQueue.TryEnqueue |
| Background tasks | Built-in, requires package identity | Available with MSIX, limited without |
| File access | Broad capabilities via manifest | Standard Win32 file access + StorageFile |
| Store APIs | Windows.Services.Store | Same (still available) |
Windows.UI.Xaml to Microsoft.UI.Xaml)Window.Current to manual tracking, CoreDispatcher to DispatcherQueue)UWP .NET 9 preview path: Microsoft announced UWP support on .NET 9 as a preview. If full WinUI 3 migration is too costly, this allows UWP apps to use modern .NET runtime features without migrating the UI framework.
For WinUI 3 development patterns, see [skill:dotnet-winui].
When cross-platform reach is needed from a UWP codebase. Uno Platform implements the WinUI XAML API surface, making it the most natural cross-platform migration path for UWP.
Since Uno Platform uses the same WinUI XAML API surface that UWP XAML is based on, much of the UWP code transfers with fewer changes than migrating to other cross-platform frameworks:
x:Bind, x:Load, etc.)Windows.* APIs needs conditional compilation or abstraction for non-Windows targetsFor Uno Platform development patterns, see [skill:dotnet-uno-platform]. For per-target deployment, see [skill:dotnet-uno-targets].
Use this matrix when deciding which migration path to take. The right choice depends on your specific constraints -- there is no universal "best" migration target.
| Goal | Recommended Path | Alternative |
|---|---|---|
| Lowest risk, fastest migration | WPF/WinForms to .NET 8+ | -- |
| Modern Windows UI | WPF to WinUI 3 | WPF .NET 9+ with Fluent theme |
| Cross-platform from Windows app | WPF to Uno Platform | Rewrite critical paths in Blazor |
| Cross-platform from UWP | UWP to Uno Platform | UWP to WinUI 3 (stay Windows-only) |
| UWP modernization (Windows-only) | UWP to WinUI 3 | UWP on .NET 9 preview |
| Legacy WinForms modernization | WinForms to .NET 8+ | Gradual rewrite in Blazor or WPF |
| Constraint | Best Path | Rationale |
|---|---|---|
| Limited budget/time | .NET 8+ migration (same framework) | Lowest effort, same codebase |
| Must stay Windows-only | WinUI 3 or WPF .NET 8+ | WinUI for modern UI; WPF for minimal change |
| Must go cross-platform | Uno Platform | Broadest reach with WinUI XAML surface |
| Large existing WPF codebase | WPF .NET 8+ first, then evaluate | Stabilize on modern runtime before UI rewrite |
| Existing UWP codebase | WinUI 3 (Windows) or Uno (cross-platform) | Closest API surface to existing code |
| Team has web skills | Blazor (rewrite) | Leverage web expertise for desktop/mobile |
For large applications, a staged approach reduces risk:
This approach avoids the "big bang" rewrite risk and delivers incremental value at each stage.
dotnet-upgrade-assistant without running analyze first. Always analyze before upgrading to understand the scope of changes and potential issues.Window, DataContext vs x:Bind, NavigationView patterns). Migration requires more than namespace changes.Window.Current, CoreDispatcher, CoreApplication APIs are all replaced with different patterns.