Migrar uma aplicação UWP para o WinUI 3

A UWP já não está em desenvolvimento ativo. O WinUI 3 e o SDK de Aplicações Windows são os seus sucessores — e as ferramentas de IA podem automatizar a maior parte da migração. O principal desafio é que os modelos de IA foram treinados com anos de amostras UWP, por isso, sem orientação, eles reproduzem os padrões de que estás a tentar afastar-te. Esta página fornece ao seu agente o contexto de que necessita para fazer as coisas corretamente.

Instale o plugin do agente WinUI

A winui-uwp-migration habilidade trata automaticamente das substituições comuns:

gh copilot plugin install winui@awesome-copilot

Consulte o plugin do agente WinUI para todos os detalhes.

Tabela de substituição de API

As tabelas seguintes resumem as substituições de API mais comuns. Para o mapeamento detalhado completo — incluindo membros, propriedades e APIs menos comuns — veja Mapear APIs e bibliotecas UWP para o SDK de Aplicações Windows.

Importante

x:Bind está, por predefinição, no modo OneTime. Ao contrário de {Binding} (que, por predefinição, utiliza OneWay), x:Bind só é avaliado uma vez, a menos que especifique Mode=OneWay ou Mode=TwoWay. Durante a migração, reveja todas as expressões x:Bind que estão associadas a propriedades que mudam em tempo de execução — a ausência de Mode=OneWay causa erros do tipo «a IU não é atualizada» que passam despercebidos na compilação.

Namespaces

UWP WinUI 3
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

Encadeamento

UWP WinUI 3
CoreDispatcher DispatcherQueue
Dispatcher.RunAsync(...) DispatcherQueue.TryEnqueue(...)
CoreApplication.MainView.CoreWindow.Dispatcher this.DispatcherQueue (de um Window ou Page)

Windowing

UWP WinUI 3
ApplicationView AppWindow
ApplicationView.GetForCurrentView() AppWindow.GetFromWindowId(...)
ApplicationViewTitleBar AppWindowTitleBar
CoreWindow Microsoft.UI.Xaml.Window
SystemNavigationManager Botão de voltar via AppWindowTitleBar

Diálogos e seletores

UWP WinUI 3
MessageDialog ContentDialog (conjunto XamlRoot)
FileOpenPicker FileOpenPicker + InitializeWithWindow
FileSavePicker FileSavePicker + InitializeWithWindow
FolderPicker FolderPicker + InitializeWithWindow

Importante

Os selecionadores requerem InitializeWithWindow antes de chamar PickSingleFileAsync (ou semelhante):

var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(App.MainWindow);
WinRT.Interop.InitializeWithWindow.Initialize(picker, hwnd);

ContentDialog requer XamlRoot (não InitializeWithWindow):

var dialog = new ContentDialog { XamlRoot = this.Content.XamlRoot, ... };
await dialog.ShowAsync();

Notifications

UWP WinUI 3
Windows.UI.Notifications.ToastNotificationManager Microsoft.Windows.AppNotifications.AppNotificationManager
Windows.UI.Notifications.BadgeUpdateManager Microsoft.Windows.BadgeNotifications.BadgeNotificationManager
Windows.UI.Notifications.TileUpdateManager Os mosaicos foram preteridos — utilize notificações ou widgets

Rede e HTTP

UWP WinUI 3 (recomendado)
Windows.Web.Http.HttpClient System.Net.Http.HttpClient (portátil, sem dependência do WinRT)
Windows.Web.Syndication.SyndicationClient System.ServiceModel.Syndication.SyndicationFeed + HttpClient
Windows.Web.AtomPub.AtomPubClient System.ServiceModel.Syndication ou HTTP direto

Note

As APIs HTTP do WinRT (Windows.Web.Http) ainda funcionam em aplicações WinUI 3 empacotadas, mas os equivalentes .NET são recomendados para portabilidade, depuração mais simples e suporte mais amplo ao ecossistema (middleware, DI, mocking).

UWP WinUI 3
Frame.Navigate(typeof(MyPage)) Frame.Navigate(typeof(MyPage)) — inalterado
SystemNavigationManager.BackRequested Manipular via NavigationView ou AppWindow
Windows.UI.Core.Preview.SystemNavigationManagerPreview evento AppWindow.Closing

Note

Navegação personalizada com menu hambúrguer (SplitView + NavMenuListView): Muitos exemplos de UWP implementaram a navegação usando um AppShell.xaml personalizado com SplitView e um controlo NavMenuListView desenvolvido manualmente (~500+ linhas). No WinUI 3, substitua todo este padrão pelo NavigationView, que oferece a mesma experiência de utilizador com acessibilidade incorporada, comportamento responsivo e suporte para botões retroativos. Isto é tipicamente uma redução de 80% no código.

Padrões MVVM

UWP (implementações personalizadas comuns) WinUI 3 (recomendado)
Personalizado BindableBase / ObservableObject CommunityToolkit.Mvvm.ComponentModel.ObservableObject
Personalizado DelegateCommand / RelayCommand CommunityToolkit.Mvvm.Input.RelayCommand
Manual SetProperty + OnPropertyChanged [ObservableProperty] Gerador de fonte
Personalizado INavigationService Integrado Frame.Navigate + NavigationView

Tip

O pacote NuGet CommunityToolkit.Mvvm é a base recomendada MVVM para aplicações WinUI 3. Substitui as classes de base criadas manualmente por equivalentes testados e gerados a partir do código-fonte — eliminando centenas de linhas de código repetitivo.

dotnet add package CommunityToolkit.Mvvm

Ciclo de vida do aplicativo

UWP WinUI 3
Application.Current.Suspending Microsoft.Windows.AppLifecycle (requer alterações arquitetónicas — ver nota)
Application.Current.Resuming AppInstance.GetCurrent().Activated (ver nota)
BackgroundTaskBuilder SDK de Aplicações Windows: tarefas em segundo plano

Note

A migração do ciclo de vida da aplicação WinUI 3 não é uma simples troca de nomes de API. O SDK de Aplicações Windows utiliza um modelo diferente de ativação e suspensão. Trate o código do ciclo de vida como se exigisse uma reescrita dedicada em vez de substituição automática. Consulte a documentação do ciclo de vida SDK de Aplicações Windows para o modelo completo.

Definições e armazenamento

UWP WinUI 3 (embalado) WinUI 3 (não embalado)
ApplicationData.Current.LocalSettings Inalterado ❌ Gera erro — sem identidade de pacote
ApplicationData.Current.LocalFolder Inalterado ❌ Gera erro — sem identidade de pacote
Windows.Storage.KnownFolders Inalterado ❌ Gera erro — sem identidade de pacote

Warning

As aplicações não empacotadas não podem usar ApplicationData.Current — gera um erro em tempo de execução porque não há identidade de pacote. Use APIs padrão de ficheiros .NET em vez disso:

var appData = Path.Combine(
    Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
    "YourAppName");
Directory.CreateDirectory(appData);
var json = JsonSerializer.Serialize(data);
await File.WriteAllTextAsync(Path.Combine(appData, "settings.json"), json);

Note

Se a sua aplicação UWP usava DataContractSerializer com [DataMember]/[IgnoreDataMember], considere migrar para System.Text.Json (mais rápida, mais compacta, com suporte para geração de código). O mapeamento de atributos é:

  • [DataMember] → [JsonPropertyName("name")] (ou simplesmente usar nomes de propriedades diretamente)
  • [IgnoreDataMember] → [JsonIgnore]
  • [DataContract] → Não é necessário equivalente (System.Text.Json serializa propriedades públicas por defeito)

APIs que não mudam

Windows.Devices.*, Windows.Media.*, Windows.UI.ViewManagement.UISettings, Windows.UI.Color e a maioria das APIs WinRT fora do espaço de nomes XAML mantêm-se inalteradas.

Controlos sem equivalente direto

Alguns controlos UWP não existem no WinUI 3. Escolha um substituto com base no seu cenário:

Controlo UWP Alternativa ao WinUI 3 Observações
Pivot TabView, NavigationView (modo superior), ou RadioButtons + visibilidade Para 2–3 abas fixas, RadioButtons com comutação de visibilidade é o mais simples. Para separadores dinâmicos/que podem ser fechados, use TabView.
RadialController Interoperação WinRT com controlo de janela RadialController.CreateForCurrentView() não tem equivalente direto. Utilizar o RadialControllerInterop com o GetForWindow(hwnd).
SystemNavigationManager Botão traseiro personalizado ou NavigationView.IsBackEnabled SystemNavigationManager.GetForCurrentView() não existe. Adiciona o teu próprio botão de retrocesso ou usa o botão de retrocesso incorporado do NavigationView.

Tinta, Win2D e impressão

Estes subsistemas requerem passos específicos de migração para além das alterações no namespace.

Tinta do Windows

O WinUI inclui InkCanvas, InkToolbar, e InkPresenter como APIs experimentais em versões experimentais do SDK de Aplicações Windows. Os lançamentos estáveis não os incluem. Para configuração, personalização da barra de ferramentas e limitações conhecidas, veja Controlos de tinta para aplicações WinUI.

Em versões experimentais, os controlos e as classes que processam a entrada de tinta estão em Microsoft.UI.Xaml.Controls. Traços e atributos de desenho mantêm-se em Windows.UI.Input.Inking:

UWP WinUI 3 (lançamentos experimentais)
Windows.UI.Xaml.Controls.InkCanvas, InkToolbar, e os outros tipos de InkToolbar* Microsoft.UI.Xaml.Controls, nomes do mesmo tipo. Alguns membros divergem.
Windows.UI.Input.Inking.InkPresenter, InkStrokeContainer, InkUnprocessedInput, InkSynchronizer, InkHighContrastAdjustment, InkStrokesCollectedEventArgs, InkInputProcessingConfiguration, InkInputRightDragAction, InkInputProcessingMode, InkInputConfiguration, InkStrokeInput, InkStrokesErasedEventArgs Microsoft.UI.Xaml.Controls, nomes do mesmo tipo. Alguns membros divergem.
Windows.UI.Input.Inking.InkStroke, InkDrawingAttributes, InkPoint, InkStrokeBuilder, InkPersistenceFormat, PenTipShape Sem alterações
Windows.UI.Core.CoreInputDeviceTypes Sem alterações

Cada tipo de UWP nas duas primeiras linhas tem um equivalente com o mesmo nome, mas o SDK de Aplicações Windows 2.5.4-experimental não inclui todos os seus membros:

  • InkStrokeContainer não tem construtor público e InkPresenter.StrokeContainer é apenas de leitura. Para alternar entre conjuntos de traços, guarde cada conjunto com SaveAsync e restaure-o com LoadAsync, que substitui os traços atuais.
  • SaveAsync e LoadAsync retornam IAsyncAction, por isso não reportam progresso, e SaveAsync não devolve o número de bytes que escreveu.
  • InkStrokeContainer.GetRecognitionResults, InkStrokeContainer.UpdateRecognitionResults, e InkInputConfiguration.IsPenHapticFeedbackEnabled não estão disponíveis.
  • InkToolbarRulerButton.Ruler e o evento InkToolbar.IsRulerButtonCheckedChanged não estão disponíveis. O UWP foi preterido InkToolbarRulerButton em favor de InkToolbarStencilButton, por isso use o botão de estêncil e o evento InkToolbar.IsStencilButtonCheckedChanged em vez disso.

O SDK de Aplicações Windows 2.4.1-experimental adicionou APIs de borracha, como InkToolbarEraserKind e InkToolbarEraserButton.SelectedEraser, que foram removidas na 2.5.4-experimental. Nunca fizeram parte do UWP, por isso não os adicione ao código migrado. Para a lista completa, veja Alterações em relação à 2.4.1-experimental.

Como tipos como InkPresenter e InkStrokeContainer existem em ambos os namespaces, importar ambos Microsoft.UI.Xaml.Controls e Windows.UI.Input.Inking causa o erro CS0104 ao usar esses nomes. Importa Microsoft.UI.Xaml.Controls, e adiciona diretivas de alias para os Windows.UI.Input.Inking tipos que usas:

using Microsoft.UI.Xaml.Controls;
using InkDrawingAttributes = Windows.UI.Input.Inking.InkDrawingAttributes;
using InkStroke = Windows.UI.Input.Inking.InkStroke;

InkStrokeContainer.SaveAsync escreve para um IOutputStream, e LoadAsync lê a partir de um IInputStream. Para usar System.IO fluxos de ficheiros, converta-os com AsOutputStream e AsInputStream. O ficheiro precisa de using System; para aguardar estes métodos do Windows Runtime, juntamente com using System.IO; e using Windows.Storage.Streams;:

// Save ink strokes to a file.
using (FileStream fileStream = File.Create(filePath))
using (IOutputStream output = fileStream.AsOutputStream())
{
    await inkStrokeContainer.SaveAsync(output);
    await output.FlushAsync();
}

// Load ink strokes from a file.
using (FileStream fileStream = File.OpenRead(filePath))
using (IInputStream input = fileStream.AsInputStream())
{
    await inkStrokeContainer.LoadAsync(input);
}

Podes continuar a ligar a barra de ferramentas ao ecrã com InkToolbar.TargetInkCanvas, ou definir TargetInkPresenter para a ligar diretamente a um InkPresenter. Para adicionar as suas próprias ferramentas à barra de ferramentas, use InkToolbarCustomToolButton e InkToolbarCustomToggleButton, como mostrado em Personalizar a barra de ferramentas de tinta. Antes de migrar, reveja as limitações conhecidas, como problemas reportados com os estênceis da régua e do transportador.

Se a sua aplicação tiver de usar uma versão estável, não existe controlo de escrita à tinta incorporado para migrar para ele. Renderiza os traços com Win2D e processa tu mesmo a entrada do ponteiro, ou usa uma biblioteca de escrita à mão de terceiros. Para substituir InkToolbar, use a CommandBar com AppBarToggleButton itens.

Win2D

O nome do pacote Win2D mudou, mas a superfície da API é idêntica:

UWP WinUI 3
Win2D.uwp (NuGet) Microsoft.Graphics.Win2D (NuGet)

Todas Microsoft.Graphics.Canvas.* as APIs (CanvasDevice, CanvasBitmap, CanvasRenderTarget, DrawInk) funcionam da mesma forma. Só a referência do pacote NuGet precisa de ser atualizada.

Impressão

A impressão UWP utiliza PrintManager.GetForCurrentView(). O WinUI 3 requer interoperação entre janelas:

// UWP
var printManager = PrintManager.GetForCurrentView();
printManager.PrintTaskRequested += OnPrintTaskRequested;
await PrintManager.ShowPrintUIAsync();

// WinUI 3 — must pass window handle
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(App.MainWindow);
var printManager = PrintManagerInterop.GetForWindow(hwnd);
printManager.PrintTaskRequested += OnPrintTaskRequested;
await PrintManagerInterop.ShowPrintUIForWindowAsync(hwnd);

As PrintDocument APIs de renderização (Paginate, GetPreviewPage, AddPages) mantêm-se inalteradas.

Importante

Se omitir o identificador da janela, PrintManagerInterop.GetForWindow gera uma COMException. Este é o mesmo padrão de interoperabilidade que FileOpenPicker — qualquer API que usava GetForCurrentView() em UWP precisa de um identificador de janela no WinUI 3.

Prompt inicial

I'm migrating a UWP app to WinUI 3 using the Windows App SDK.

Apply these substitutions:
- Windows.UI.Xaml.* → Microsoft.UI.Xaml.*
- CoreDispatcher / Dispatcher.RunAsync → DispatcherQueue.TryEnqueue
- ApplicationView → AppWindow + AppWindowTitleBar
- CoreWindow → Microsoft.UI.Xaml.Window
- MessageDialog → ContentDialog (set XamlRoot, not InitializeWithWindow)
- FileOpenPicker / FileSavePicker / FolderPicker → add InitializeWithWindow
- Windows.UI.Notifications → Microsoft.Windows.AppNotifications
- SystemNavigationManager.BackRequested → NavigationView back handling
- Pivot → TabView, NavigationView (top mode), or RadioButtons (no direct equivalent)
- InkCanvas, InkToolbar, InkPresenter, InkStrokeContainer, and the other ink input types → Microsoft.UI.Xaml.Controls (experimental Windows App SDK releases only; if the project uses a stable release, flag them instead)
- Ink members that Windows App SDK 2.5.4-experimental doesn't include (new InkStrokeContainer(), assignments to InkPresenter.StrokeContainer, GetRecognitionResults, UpdateRecognitionResults, IsPenHapticFeedbackEnabled, InkToolbarRulerButton.Ruler, IsRulerButtonCheckedChanged, and progress or byte counts from SaveAsync and LoadAsync) → flag them
- PrintManager.GetForCurrentView → PrintManagerInterop.GetForWindow(hwnd)
- Win2D.uwp NuGet → Microsoft.Graphics.Win2D NuGet
- InkStroke, InkDrawingAttributes, InkPoint, InkStrokeBuilder → no change (Windows.UI.Input.Inking; use using aliases to avoid CS0104)

Do not use any Windows.UI.Xaml.* namespaces in new code.
Do not use CoreDispatcher — use DispatcherQueue.
Do not add InkToolbarEraserKind, SelectedEraser, or other eraser APIs from Windows App SDK 2.4.1-experimental. Version 2.5.4-experimental removed them.
x:Bind defaults to Mode=OneTime. Add Mode=OneWay for any binding that should update at runtime.
Flag any APIs without a direct WinUI 3 equivalent rather than guessing.

Alterações no ficheiro Project

Substituir a estrutura alvo do UWP:

<!-- Before (UWP) -->
<TargetPlatformVersion>10.0.19041.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>

<!-- After (WinUI 3) -->
<TargetFramework>net10.0-windows10.0.19041.0</TargetFramework>
<WindowsSdkPackageVersion>10.0.19041.31</WindowsSdkPackageVersion>

Adicionar o pacote do SDK de Aplicações Windows:

dotnet add package Microsoft.WindowsAppSDK