Edit

Upgrade a WPF app to .NET with GitHub Copilot modernization

This article walks through upgrading a WPF desktop app to .NET by using the GitHub Copilot modernization agent. The agent runs in your editor, analyzes the project, and drives a three-stage workflow: assessment, planning, and execution.

The example uses the Matching Game sample, a small .NET Framework WPF app made up of a main project and a class library.

Prerequisites

Tip

Be sure to have a backup of your code, such as in source control or a copy, before you start.

Open the solution

The Matching Game projects target .NET Framework 4.5. Visual Studio prompts you to retarget the projects to a supported version of .NET Framework when you open the solution.

  1. Open the MatchingGame solution in Visual Studio.
  2. Visual Studio displays the Target Framework Not Installed dialog.
  3. Select Update the target to .NET Framework 4.8 (Recommended), and then select Continue.
  4. Open the Git Changes window and commit the retargeting changes.

Important notes for Visual Basic

The GitHub Copilot modernization agent doesn't fully support Visual Basic .NET projects. The agent includes guardrails specifically designed to ensure C# projects upgrade reliably, and those guardrails interfere with VB project analysis and execution. If your solution contains VB projects, use one of these alternatives instead:

  • GitHub Copilot (standard agent): Use the regular Copilot agent—without the modernization agent—to guide the upgrade interactively.
  • Install .NET Upgrade Assistant: A dedicated migration tool with VB support.

Tip

If your solution contains both C# and VB projects, you can still use the modernization agent for the C# projects. Upgrade the VB projects separately using one of the alternatives listed above.

If you use the standard Copilot agent or upgrade manually, follow these steps:

  1. If the project targets an unsupported version of .NET Framework, retarget it to .NET Framework 4.8 first. Visual Studio prompts you to do this when you open the solution, or you can change it in the project properties.

  2. Update any outdated NuGet packages to their latest compatible versions.

  3. Create a new VB WPF project using a Visual Studio template or dotnet new wpf -lang vb. The template produces an SDK-style project file and settings, which have changed from .NET Framework.

  4. Copy your .vb source files from the old project folder to the new project folder.

  5. Copy any non-code files the project depends on, such as app.config, .settings files, images, icons, and other embedded resources.

  6. Open the old project file (or packages.config) and note every NuGet package reference. Add those same packages to the new project using the NuGet Package Manager or dotnet add package <name>.

  7. If the project references other projects in the solution, re-add those references in the new project.

  8. Attempt to build the solution. Don't fix errors yet — the build output gives Copilot a concrete list of issues to work from.

  9. Commit the current state to source control so you have a clean baseline before Copilot makes changes.

  10. Open GitHub Copilot Chat, and ask it to resolve the remaining issues. For example:

    This Visual Basic WPF project was migrated from .NET Framework 4.8 to .NET 10. The project file and source files are in place, but the solution doesn't compile. Review the build errors and fix API incompatibilities, missing references, and any configuration migration issues.

  11. Review the changes Copilot proposes, then rebuild and test the project.

Initiate the upgrade

The Matching Game solution contains the MatchingGame app and the MatchingGame.Logic class library. The agent figures out the project graph on its own, so start the upgrade at the solution level.

  1. In Solution Explorer, right-click the solution and select Modernize.

    The GitHub Copilot Chat window opens and starts a conversation with the modernization agent.

  2. Select a model with strong reasoning and coding capabilities.

  3. Tell the agent what you want to do. For example:

    Upgrade everything to .NET 10.

    The agent reports the current state of the codebase and what it plans to do:

    • Target Framework: Indicates that the agent upgrades the projects to .NET 10.
    • Flow Mode: Defaults to Automatic. For complex apps, ask the agent to switch to Guided mode.
    • Source Control: Indicates that the agent creates a new working branch.

    The agent writes its work to .github/upgrades/scenarios/dotnet-version-upgrade/ in your repository. If that folder already exists from a prior attempt, the agent asks whether to continue or start fresh.

  4. Tell the agent start to begin the upgrade process.

Review the assessment

In the assessment stage, the agent examines the project structure, dependencies, and code patterns to identify what needs to change. It writes the results to assessment.md in .github/upgrades/scenarios/dotnet-version-upgrade/.

When Copilot finishes the assessment, review the conversation output. It generally starts with something similar to the following:

Assessment Complete

I've analyzed the solution and created a full assessment — see .github/upgrades/scenarios/dotnet-version-upgrade/assessment.md.

Solution: MatchingGame.slnx → target: net10.0

Compatibility Statistics:

- Projects: 2 (both currently on net48, legacy project format)
- Issues: 100 (Mandatory: 91, Potential: 9, Optional: 0)
- Affected Files: 6
- Affected Technologies: WPF (61 issues), Legacy Configuration System (2 issues)

Projects:

| Project                                      | Current TFM | Type                  |
|----------------------------------------------|-------------|-----------------------|
| MatchingGame.Logic\MatchingGame.Logic.csproj | net48       | Classic Class Library |
| MatchingGame\MatchingGame.csproj             | net48       | Classic WPF           |

Key issues found:

- Both projects use legacy (non-SDK-style) project format → must be converted to SDK-style
- Both project target frameworks need to change to net10.0
- WPF project (MatchingGame.csproj) has binary/source/behavioral API incompatibilities and Legacy Configuration System usage

No security vulnerabilities were detected, and no NuGet packages are referenced — this is a self-contained WPF + library solution.
Proceeding to planning now. You can ask me to pause and switch to Guided mode at any time.

Review the upgrade options

After the assessment, the agent presents upgrade strategy decisions and saves them to upgrade-options.md in .github/upgrades/scenarios/dotnet-version-upgrade/. For the Matching Game sample, the agent selects the following options:

Aspect Decision Reason
Upgrade strategy Bottom-up. The agent upgrades MatchingGame.Logic first because MatchingGame depends on it, then validates each tier before moving on.
Project approach In-place. Both projects migrate together because no other .NET Framework projects consume them.
Unsupported API handling Fix inline. Most WPF API changes for .NET are mechanical and don't require a separate planning pass.
Windows native APIs Windows Compatibility Pack. The app uses the registry and is inherently Windows-only.
Nullable reference types Leave disabled. The agent treats enabling nullable as a separate effort after migration.

The agent also calls out risks that need your attention. Review the proposed options and tell the agent what you want to change. For example, tell the agent to enable nullable reference types or to change how incompatible packages are handled. When you're done, reply confirm to lock in the selections and move to planning.

Review the plan

In the planning stage, the agent converts the assessment and your confirmed options into a detailed specification. It writes the result to plan.md and creates a scenario-instructions.md file that stores preferences, decisions, and custom instructions for the upgrade.

Important

If Flow Mode is Automatic, the agent starts executing the plan without time to review.

The plan covers items such as the upgrade order across projects, the target framework moniker for each project (net10.0-windows for WPF projects), package update paths, and risk mitigations for the breaking changes the assessment found.

To review and customize the plan:

  1. Open plan.md in .github/upgrades/scenarios/dotnet-version-upgrade/.
  2. Review the upgrade strategies and dependency updates.
  3. Edit the plan to adjust steps or add context as needed.
  4. Tell the agent to move to the execution stage.

Caution

The plan depends on project interdependencies. The upgrade doesn't succeed if you modify the plan in a way that prevents the upgrade path from completing. For example, if MatchingGame depends on MatchingGame.Logic and you remove MatchingGame.Logic from the plan, upgrading MatchingGame might fail.

Run the upgrade

In the execution stage, the agent breaks the plan into sequential, concrete tasks with validation criteria. The agent writes the task list to .github/upgrades/scenarios/dotnet-version-upgrade/tasks.md and tracks overall progress in that file. For each task, the agent creates a folder under .github/upgrades/scenarios/dotnet-version-upgrade/tasks/ that contains a Markdown file describing the task and a markdown file that reports the task's progress.

For the Matching Game sample, the task list typically includes upgrading MatchingGame.Logic first, then MatchingGame, restoring packages, building the solution, and committing the changes.

To run the upgrade:

  1. Tell the agent to start the upgrade.
  2. Monitor progress by reviewing tasks.md as the agent updates task statuses. Open the per-task folders under tasks/ for the task description and a detailed progress report.
  3. If the agent encounters a problem it can't resolve, provide the requested help. For example, the agent might ask you to choose between two replacement APIs or confirm whether to keep a deprecated package.
  4. Based on your responses, the agent adapts its strategy to the remaining tasks and continues.

The agent commits changes according to the Git strategy you configured during pre-initialization: per task, per group of tasks, or at the end.

Notes for Visual Basic projects

Visual Basic WPF projects on .NET Framework often use System.Configuration settings files and My extensions, such as My.Computer and My.User. The My extensions were removed in .NET. The agent flags these patterns during assessment and proposes fixes during execution, but you might need to confirm individual changes during a guided run.

If the agent migrates the project but it doesn't compile, verify that the project file targets Windows and references WPF. The <PropertyGroup> element should look like the following snippet:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net10.0-windows</TargetFramework>
    <UseWPF>true</UseWPF>
    <OutputType>WinExe</OutputType>
    <MyType>Windows</MyType>

    <!-- Other settings removed for brevity. -->
  </PropertyGroup>
</Project>

Verify the upgrade

When the upgrade finishes, the agent recommends next steps in the chat response. Prompt the agent to generate a comprehensive change report with "Generate a change report."

Review the final task status in tasks.md and confirm that every step is complete.

To verify the upgrade:

  1. Build the solution and address any compilation errors.
  2. Run the app and confirm that windows and views load and behave as expected. Review any visual or behavioral differences in XAML controls and custom controls between .NET Framework and .NET.
  3. Run any unit tests in the solution and fix failures.
  4. Confirm that updated NuGet packages are compatible with your app.
  5. Test the app thoroughly to verify the upgrade succeeded.

Tip

If the project won't run and a debugger can't be attached, try restarting Visual Studio. Migrating project files from .NET Framework to .NET might confuse the WPF designer without a restart.

The WPF Matching Game Sample is now upgraded to .NET 10.

Post-upgrade experience

If you ported the app from .NET Framework to .NET, review Modernize your upgraded .NET Framework apps for ideas on adopting newer patterns, such as appsettings.json configuration, dependency injection, or cloud services. Adopting these patterns is separate from upgrading to .NET and isn't required to complete the upgrade.