Migrating from WinForms to WPF, WinUI or Blazor Hybrid
Inventory a legacy codebase, separate business logic from UI, migrate incrementally with interop, and compare the replacement stacks honestly.
Inventory before you rewrite
A WinForms application hides its business rules in event handlers. The first job is to find out how much of the code is genuinely about orders and how much is about pixels - the ratio decides whether a migration is worth doing at all.
- List every form and count the lines in code-behind. Forms over a few hundred lines of logic are the ones to attack first.
- Mark every place the UI touches the database, the network or the file system directly. Those are the seams where a service layer should go.
- Find the controls with no modern equivalent or with different behaviour:
DataGridView,PropertyGrid, third-party gauges. - Write a smoke test that exercises the core workflow with no UI at all. If you cannot, the logic is still trapped and extraction comes first.
- Count the third-party control licences - replacing a grid is often the largest single line of a migration budget.
// before: the rule lives in the click handler
private void OnApprove(object sender, EventArgs e)
{
if (orderGrid.CurrentRow?.DataBoundItem is Order o && o.Total < 500)
{
o.Status = "Approved";
_repo.Save(o);
orderGrid.Refresh();
}
}
// after: the rule is testable and the UI only calls it
public sealed class OrderService
{
public Result Approve(Order order)
{
if (order.Total >= 500m)
return Result.Fail("Orders over 500 need a second approver.");
order.Status = OrderStatus.Approved;
_repo.Save(order);
return Result.Ok();
}
}
private void OnApprove(object sender, EventArgs e)
{
if (orderGrid.CurrentRow?.DataBoundItem is not Order o) return;
var result = _service.Approve(o);
if (!result.Succeeded) errors.SetError(approveButton, result.Message);
}Choosing the target
| Stack | Strengths | Costs | Pick it when |
|---|---|---|---|
| WPF | Mature, deep control ecosystem, XAML, MVVM | Learning curve for binding and templates | A long-lived desktop app on .NET |
| WinUI 3 | Modern controls, fluent design, Windows App SDK | Ecosystem still smaller than WPF's | A new Windows-only app with a modern look |
| Blazor Hybrid | Web UI skills, one component model, MAUI host | WebView overhead; heavy data grids stay hard | Your team is strongest in web technologies |
| MAUI | One codebase across desktop and mobile | Desktop fidelity gaps; churn in the tooling | You also need mobile from the same code |
| Stay on WinForms | Zero migration cost, everything already works | Dated UI, no dark mode story, weaker testability | The app is stable and rarely touched |
A rewrite is justified by a business driver - new platforms, a new design language, hiring difficulty - not by the age of the framework. A stable internal tool that works is not a problem to be solved.
Migrating incrementally
// host a WinForms control inside a WPF window while you migrate screen by screen
public partial class LegacyHost : System.Windows.Forms.Integration.WindowsFormsHost
{
public LegacyHost()
{
Child = new OrderGridControl(); // the untouched WinForms control
}
}
// and the reverse: a WPF control inside a WinForms form, via element host
var host = new ElementHost { Dock = DockStyle.Fill, Child = new WpfSummaryView() };
panel.Controls.Add(host);- Migrate screen by screen behind a shell that can host both, so the application stays shippable at every step.
- Mixing
WindowsFormsHostandElementHosthas airspace and DPI limitations: a hosted control always renders on top, and per-monitor scaling needs both stacks to agree. - Move the business logic first, the UI second. Logic extracted with no test coverage will be rewritten twice.
- Freeze new features on the old screens. Two live UI styles in one product is a temporary state with a deadline, not a destination.
⚠️
Do not start a migration without an end date for the parallel period. Interop layers are easy to add and very hard to remove: two years later you will have two UI stacks, two theming systems and a maintenance bill for both.
FAQ
Can I convert XAML back to WinForms?
No, and there is no automated WinForms-to-XAML converter worth the risk. The designer files are a serialised object graph; a mechanical translation produces XAML that compiles and looks wrong.
Is WinForms dead?
No. It is still supported on current .NET and receives fixes and dark-mode support. It is simply no longer the recommended choice for new applications that need a modern UI.
Related
Deployment: ClickOnce, MSIX and single-file Forms and controls
Last refreshed 2026-09-18.