Migrar um aplicativo UWP para o WinUI 3

A UWP não está mais em desenvolvimento ativo. O WinUI 3 e o SDK do Aplicativo Windows são 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 em anos de exemplos UWP, portanto, sem orientação, eles reproduzem os padrões dos quais você está tentando se afastar. Esta página fornece ao seu agente o contexto necessário para acertar.

Instalar o plug-in do agente WinUI

A habilidade winui-uwp-migration faz automaticamente as substituições comuns:

gh copilot plugin install winui@awesome-copilot

Consulte o plug-in do agente WinUI para obter detalhes completos.

Tabela de substituição de API

As tabelas a seguir resumem as substituições de API mais comuns. Para obter o mapeamento completo e detalhado — incluindo membros, propriedades e APIs menos comuns — consulte Mapeando APIs e bibliotecas UWP para o SDK do Aplicativo Windows.

Importante

x:Bind usa o modo OneTime por padrão. Diferentemente {Binding} (que usa como padrão OneWay), x:Bind só é avaliado uma vez, a menos que você especifique Mode=OneWay ou Mode=TwoWay. Durante a migração, audite todas as expressões x:Bind que se vinculam a propriedades que mudam em tempo de execução — a ausência de Mode=OneWay causa bugs de "a interface do usuário não é atualizada" que são invisíveis em tempo de 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

Threading

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 Voltar por meio de AppWindowTitleBar

Caixas de diálogo e seletores

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

Importante

Os seletores exigem 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();

Notificações

UWP WinUI 3
Windows.UI.Notifications.ToastNotificationManager Microsoft.Windows.AppNotifications.AppNotificationManager
Windows.UI.Notifications.BadgeUpdateManager Microsoft.Windows.BadgeNotifications.BadgeNotificationManager
Windows.UI.Notifications.TileUpdateManager Os blocos são preteridos – use 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 aplicativos WinUI 3 empacotados, 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 do tipo hambúrguer (SplitView + NavMenuListView): Muitos exemplos de UWP implementavam a navegação usando um AppShell.xaml personalizado com SplitView e um controle NavMenuListView desenvolvido manualmente (aproximadamente mais de 500 linhas). No WinUI 3, substitua todo esse padrão pelo NavigationView, que fornece o mesmo UX com acessibilidade interna, comportamento responsivo e suporte a botão voltar. Normalmente, isso é uma redução de código de 80%.

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 código-fonte
PersonalizarINavigationService Interno Frame.Navigate + NavigationView

Dica

O pacote NuGet CommunityToolkit.Mvvm é a base MVVM recomendada para aplicativos WinUI 3. Substitui classes 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 — consulte a observação)
Application.Current.Resuming AppInstance.GetCurrent().Activated (consulte a nota)
BackgroundTaskBuilder Tarefas em Segundo Plano do SDK do Aplicativo Windows

Note

A migração do ciclo de vida do aplicativo WinUI 3 não é uma simples troca de nomes de API. O SDK do Aplicativo Windows usa um modelo de ativação e suspensão diferente. Trate o código do ciclo de vida como exigindo uma reescrita dedicada em vez de uma substituição automatizada. Consulte a documentação do ciclo de vida SDK do Aplicativo Windows para obter o modelo completo.

Configurações e armazenamento

UWP WinUI 3 (empacotado) WinUI 3 (não empacotado)
ApplicationData.Current.LocalSettings Inalterado ❌ Lançamentos – sem identidade de pacote
ApplicationData.Current.LocalFolder Inalterado ❌ Lançamentos – sem identidade de pacote
Windows.Storage.KnownFolders Inalterado ❌ Lançamentos – sem identidade de pacote

Warning

Aplicativos não empacotados não podem ser usados ApplicationData.Current – ele é lançado em runtime porque não há nenhuma identidade de pacote. Em vez disso, use APIs de arquivo de .NET padrão:

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 o seu aplicativo UWP usava DataContractSerializer com [DataMember]/[IgnoreDataMember], considere migrar para System.Text.Json (mais rápido, menor, com suporte à geração de código-fonte). O mapeamento do atributo é:

  • [DataMember] → [JsonPropertyName("name")] (ou apenas use os nomes de propriedade diretamente)
  • [IgnoreDataMember] → [JsonIgnore]
  • [DataContract] → Nenhum equivalente necessário (System.Text.Json serializa propriedades públicas por padrão)

APIs que não mudam

Windows.Devices.*, Windows.Media.*, Windows.UI.ViewManagement.UISettings, Windows.UI.Color e a maioria das APIs do WinRT fora do namespace XAML não são alteradas.

Controles sem um equivalente direto

Alguns controles UWP não existem no WinUI 3. Escolha uma substituição com base em seu cenário:

Controle UWP Substituto do WinUI 3 Notes
Pivot TabView, NavigationView (modo superior) ou RadioButtons + visibilidade Para 2–3 guias fixas, RadioButtons com alternância de visibilidade é mais simples. Para abas dinâmicas/fecháveis, use TabView.
RadialController Interoperabilidade do WinRT com manipulador de janela RadialController.CreateForCurrentView() não tem equivalente direto. Usar o RadialControllerInterop com o GetForWindow(hwnd).
SystemNavigationManager Botão Voltar personalizado ou NavigationView.IsBackEnabled SystemNavigationManager.GetForCurrentView() não existe. Adicione seu próprio botão Voltar ou use o botão Voltar integrado de NavigationView.

Tinta, Win2D e impressão

Esses subsistemas exigem etapas de migração específicas além das alterações de namespace.

Tinta do Windows

O WinUI inclui InkCanvas, InkToolbare InkPresenter como APIs experimentais em versões experimentais do SDK do Aplicativo Windows. As versões estáveis não as incluem. Para configuração, personalização da barra de ferramentas e limitações conhecidas, consulte controles de escrita à tinta para aplicativos WinUI.

Em versões experimentais, os controles e os tipos que processam a entrada por tinta estão em Microsoft.UI.Xaml.Controls. Traços e atributos de desenho permanecem em Windows.UI.Input.Inking:

UWP WinUI 3 (versões experimentais)
Windows.UI.Xaml.Controls.InkCanvas, InkToolbare os outros InkToolbar* tipos Microsoft.UI.Xaml.Controls, os mesmos nomes de tipo. Alguns membros diferem.
Windows.UI.Input.Inking.InkPresenter, InkStrokeContainer, InkStrokeInput, InkUnprocessedInput, InkSynchronizer, InkInputConfiguration, InkInputProcessingConfiguration, InkInputProcessingMode, InkInputRightDragAction, InkHighContrastAdjustment, InkStrokesCollectedEventArgs, InkStrokesErasedEventArgs Microsoft.UI.Xaml.Controls, os mesmos nomes de tipo. Alguns membros diferem.
Windows.UI.Input.Inking.InkStroke, InkDrawingAttributes, InkPoint, InkStrokeBuilder, InkPersistenceFormat, PenTipShape Nenhuma alteração
Windows.UI.Core.CoreInputDeviceTypes Nenhuma alteração

Cada tipo UWP nas duas primeiras linhas tem um equivalente com o mesmo nome, mas o SDK do Aplicativo Windows 2.5.4-experimental não inclui todos os membros deles:

  • InkStrokeContainer não tem construtor público e InkPresenter.StrokeContainer é somente leitura. Para alternar entre conjuntos de traços, salve cada conjunto SaveAsync e restaure-o com LoadAsync, o que substitui os traços atuais.
  • SaveAsync e LoadAsync retornam IAsyncAction, portanto, não relatam o progresso, e SaveAsync não retorna o número de bytes que ele escreveu.
  • InkStrokeContainer.GetRecognitionResults, InkStrokeContainer.UpdateRecognitionResultse InkInputConfiguration.IsPenHapticFeedbackEnabled não estão disponíveis.
  • InkToolbarRulerButton.Ruler e o evento InkToolbar.IsRulerButtonCheckedChanged não estão disponíveis. Na UWP, InkToolbarRulerButton foi preterido em favor de InkToolbarStencilButton, portanto, use o botão de estêncil e o evento InkToolbar.IsStencilButtonCheckedChanged.

O SDK do Aplicativo Windows 2.4.1-experimental adicionou APIs de borracha, como InkToolbarEraserKind e InkToolbarEraserButton.SelectedEraser, que o 2.5.4-experimental removeu. Eles nunca fizeram parte da UWP, portanto, não os adicione ao código migrado. Para obter a lista completa, consulte Alterações de 2.4.1-experimental.

Como tipos como InkPresenter e InkStrokeContainer existem em ambos os namespaces, importar Microsoft.UI.Xaml.Controls e Windows.UI.Input.Inking causa o erro CS0104 ao usar esses nomes. Importe Microsoft.UI.Xaml.Controlse adicione diretivas de alias para os Windows.UI.Input.Inking tipos que você usa:

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

InkStrokeContainer.SaveAsync grava em um IOutputStreame LoadAsync lê de um IInputStream. Para usar System.IO fluxos de arquivos, converta-os com AsOutputStream e AsInputStream. O arquivo precisa de using System; para aguardar esses 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);
}

Você pode continuar conectando a barra de ferramentas ao canvas com InkToolbar.TargetInkCanvas, ou definir TargetInkPresenter para conectá-la diretamente a um InkPresenter. Para adicionar suas próprias ferramentas à barra de ferramentas, use InkToolbarCustomToolButton e InkToolbarCustomToggleButton, conforme mostrado em Personalizar a barra de ferramentas de tinta. Antes de migrar, examine as limitações conhecidas, como problemas relatados com a régua e os estênceis de transferidor.

Se o aplicativo precisar usar uma versão estável, não há controle de tinta interno para o qual migrar. Renderize traços com o Win2D e manipule a entrada do ponteiro por conta própria ou use uma biblioteca de escrita à tinta de terceiros. Para substituir InkToolbar, use um CommandBar com AppBarToggleButton itens.

Win2D

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

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

Todas as Microsoft.Graphics.Canvas.* APIs (CanvasDevice, CanvasBitmap, , CanvasRenderTarget) DrawInkfuncionam da mesma maneira. Somente a referência do pacote NuGet precisa ser atualizada.

Impressão

A impressão UWP usa PrintManager.GetForCurrentView(). O WinUI 3 requer interoperação com manipulador de janela:

// 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) não são alteradas.

Importante

Se você omitir o identificador da janela, PrintManagerInterop.GetForWindow irá gerar um COMException. Esse é o mesmo padrão de interoperabilidade de FileOpenPicker — qualquer API que usava GetForCurrentView() no UWP precisa de um identificador de janela no WinUI 3.

Prompt de início

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 arquivo do projeto

Substitua 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>

Adicione o pacote SDK do Aplicativo Windows:

dotnet add package Microsoft.WindowsAppSDK