Migración de una aplicación para UWP a WinUI 3

UWP ya no está en desarrollo activo. WinUI 3 y el SDK de Aplicaciones para Windows son sus sucesores, y las herramientas de inteligencia artificial pueden automatizar la mayor parte de la migración. El principal desafío es que los modelos de inteligencia artificial se entrenaron en años de ejemplos de UWP, por lo que sin instrucciones reproducen los patrones de los que intentas alejarte. Esta página proporciona a tu agente el contexto que necesita para hacerlo bien.

Instalación del complemento del agente de WinUI

La winui-uwp-migration función gestiona automáticamente las sustituciones comunes:

gh copilot plugin install winui@awesome-copilot

Consulte el complemento del agente de WinUI para obtener todos los detalles.

Tabla de sustitución de API

En las tablas siguientes se resumen las sustituciones de API más comunes. Para obtener la asignación detallada completa (incluidos los miembros, las propiedades y las API menos comunes), consulta Asignación de API y bibliotecas de UWP a la SDK de Aplicaciones para Windows.

Importante

x:Bind está en modo OneTime de forma predeterminada. A diferencia {Binding} de (que tiene OneWaycomo valor predeterminado ), x:Bind solo se evalúa una vez a menos que especifique Mode=OneWay o Mode=TwoWay. Durante la migración, audite todas las expresiones x:Bind que están vinculadas a propiedades que cambian durante la ejecución; la ausencia de Mode=OneWay provoca errores de "la interfaz de usuario no se actualiza" que son indetectables en tiempo de compilación.

Espacios de nombres

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 un Window o Page)

Windowing

UWP WinUI 3
ApplicationView AppWindow
ApplicationView.GetForCurrentView() AppWindow.GetFromWindowId(...)
ApplicationViewTitleBar AppWindowTitleBar
CoreWindow Microsoft.UI.Xaml.Window
SystemNavigationManager Botón de retroceso mediante AppWindowTitleBar

Cuadros de diálogo y selectores

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

Importante

Los selectores requieren InitializeWithWindow antes de llamar a PickSingleFileAsync (o algo similar):

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

ContentDialog requiere XamlRoot (no InitializeWithWindow):

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

Notificaciones

UWP WinUI 3
Windows.UI.Notifications.ToastNotificationManager Microsoft.Windows.AppNotifications.AppNotificationManager
Windows.UI.Notifications.BadgeUpdateManager Microsoft.Windows.BadgeNotifications.BadgeNotificationManager
Windows.UI.Notifications.TileUpdateManager Los iconos están en desuso: usar notificaciones o widgets

Redes y HTTP

UWP WinUI 3 (recomendado)
Windows.Web.Http.HttpClient System.Net.Http.HttpClient (portable, sin dependencia de WinRT)
Windows.Web.Syndication.SyndicationClient System.ServiceModel.Syndication.SyndicationFeed + HttpClient
Windows.Web.AtomPub.AtomPubClient System.ServiceModel.Syndication o HTTP directa

Note

Las API HTTP de WinRT (Windows.Web.Http) siguen funcionando en aplicaciones WinUI 3 empaquetadas, pero se recomiendan los equivalentes de .NET por motivos de portabilidad, una depuración más sencilla y una compatibilidad más amplia con el ecosistema (middleware, inyección de dependencias, simulación).

UWP WinUI 3
Frame.Navigate(typeof(MyPage)) Frame.Navigate(typeof(MyPage)) — sin cambios
SystemNavigationManager.BackRequested Gestionar mediante NavigationView o AppWindow
Windows.UI.Core.Preview.SystemNavigationManagerPreview AppWindow.Closing evento

Note

Navegación tipo hamburguesa personalizada (SplitView + NavMenuListView): Muchos ejemplos de UWP implementaban la navegación mediante un AppShell.xaml personalizado con SplitView y un control NavMenuListView creado a mano (más de 500 líneas). En WinUI 3, reemplace todo este patrón por NavigationView, que proporciona la misma experiencia de usuario con accesibilidad integrada, comportamiento dinámico y compatibilidad con botón atrás. Normalmente, se trata de una reducción de código de 80%.

Patrones de MVVM

UWP (implementaciones personalizadas comunes) WinUI 3 (recomendado)
Personalizado BindableBase / ObservableObject CommunityToolkit.Mvvm.ComponentModel.ObservableObject
Personalizado DelegateCommand / RelayCommand CommunityToolkit.Mvvm.Input.RelayCommand
Manual SetProperty + OnPropertyChanged [ObservableProperty] generador de código fuente
INavigationService personalizado Integrado Frame.Navigate + NavigationView

Sugerencia

El paquete NuGet CommunityToolkit.Mvvm es la base de MVVM recomendada para aplicaciones winUI 3. Reemplaza las clases base hechas manualmente por equivalentes probados generados a partir del código fuente, eliminando cientos de líneas de código repetitivo.

dotnet add package CommunityToolkit.Mvvm

Ciclo de vida de la aplicación

UWP WinUI 3
Application.Current.Suspending Microsoft.Windows.AppLifecycle (requiere cambios arquitectónicos; consulte la nota)
Application.Current.Resuming AppInstance.GetCurrent().Activated (consulte la nota)
BackgroundTaskBuilder Tareas en segundo plano del SDK de aplicaciones de Windows

Note

La migración del ciclo de vida de aplicaciones de WinUI 3 no es un intercambio simple de nombres de API. El SDK de Aplicaciones para Windows usa un modelo de activación y suspensión diferente. Trate el código del ciclo de vida como algo que requiere una reescritura específica en lugar de una sustitución automatizada. Consulte la documentación del ciclo de vida de SDK de Aplicaciones para Windows para ver el modelo completo.

Configuración y almacenamiento

UWP WinUI 3 (empaquetado) WinUI 3 (sin empaquetar)
ApplicationData.Current.LocalSettings Sin cambios ❌ Lanza una excepción: falta identidad del paquete
ApplicationData.Current.LocalFolder Sin cambios ❌ Lanza una excepción: falta identidad del paquete
Windows.Storage.KnownFolders Sin cambios ❌ Lanza una excepción: falta identidad del paquete

Warning

Las aplicaciones desempaquetadas no pueden usar ApplicationData.Current: genera un error en tiempo de ejecución porque no existe identidad de paquete. En su lugar, use las API de archivo .NET estándar:

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

Si tu aplicación para UWP usaba DataContractSerializer con [DataMember]/[IgnoreDataMember], considera migrar a System.Text.Json (más rápido, más pequeño y compatible con la generación de código fuente). La asignación de atributos es:

  • [DataMember] → [JsonPropertyName("name")] (o simplemente usar los nombres de las propiedades directamente)
  • [IgnoreDataMember] → [JsonIgnore]
  • [DataContract] → No se necesita ningún equivalente (System.Text.Json serializa las propiedades públicas de forma predeterminada)

API que no cambian

Windows.Devices.*, Windows.Media.*, Windows.UI.ViewManagement.UISettings, Windows.UI.Color y la mayoría de las API de WinRT fuera del espacio de nombres XAML no cambian.

Controles sin un equivalente directo

Algunos controles de UWP no existen en WinUI 3. Elija un reemplazo en función de su escenario:

Control de UWP Reemplazo de WinUI 3 Notas
Pivot TabView, NavigationView (modo superior) o RadioButtons + visibilidad Para 2 o 3 pestañas fijas, RadioButtons con alternancia de visibilidad es lo más sencillo. Para las pestañas dinámicas o que se pueden cerrar, use TabView.
RadialController Interoperabilidad de WinRT con identificador de ventana RadialController.CreateForCurrentView() no tiene equivalente directo. Usar RadialControllerInterop con GetForWindow(hwnd).
SystemNavigationManager Botón de retroceso personalizado o NavigationView.IsBackEnabled SystemNavigationManager.GetForCurrentView() no existe. Añada su propio botón de retroceso o use el botón de retroceso integrado de NavigationView.

Ink, Win2D e impresión

Estos subsistemas requieren pasos de migración específicos más allá de los cambios en el espacio de nombres.

Windows Ink

WinUI incluye InkCanvas, InkToolbary InkPresenter como API experimentales en versiones experimentales del SDK de Aplicaciones para Windows. Las versiones estables no las incluyen. Para obtener información sobre la configuración, la personalización de la barra de herramientas y las limitaciones conocidas, consulte Controles de entrada manuscrita para aplicaciones WinUI.

En versiones experimentales, los controles y los tipos que procesan la entrada manuscrita están en Microsoft.UI.Xaml.Controls. Los trazos y los atributos de dibujo permanecen en Windows.UI.Input.Inking:

UWP WinUI 3 (versiones experimentales)
Windows.UI.Xaml.Controls.InkCanvas, InkToolbary los otros InkToolbar* tipos Microsoft.UI.Xaml.Controls, los mismos nombres de tipo. Algunos miembros difieren.
Windows.UI.Input.Inking.InkPresenter, InkStrokeContainer, InkStrokeInput, InkUnprocessedInput, InkSynchronizer, InkInputConfiguration, InkInputProcessingConfiguration, InkInputProcessingMode, InkInputRightDragAction, InkHighContrastAdjustment, InkStrokesCollectedEventArgs, InkStrokesErasedEventArgs Microsoft.UI.Xaml.Controls, los mismos nombres de tipo. Algunos miembros difieren.
Windows.UI.Input.Inking.InkStroke, InkDrawingAttributes, InkPoint, InkStrokeBuilder, InkPersistenceFormat, PenTipShape Sin cambios
Windows.UI.Core.CoreInputDeviceTypes Sin cambios

Cada tipo de UWP de las dos primeras filas tiene un homólogo con el mismo nombre, pero SDK de Aplicaciones para Windows 2.5.4-experimental no incluye todos sus miembros:

  • InkStrokeContainer no tiene ningún constructor público y InkPresenter.StrokeContainer es de solo lectura. Para cambiar entre conjuntos de trazos, guarde cada conjunto con SaveAsync y restáurelo con LoadAsync, que reemplaza los trazos actuales.
  • SaveAsync y LoadAsync devuelven IAsyncAction, por lo que no notifican el progreso y SaveAsync no devuelve el número de bytes que escribió.
  • InkStrokeContainer.GetRecognitionResults, InkStrokeContainer.UpdateRecognitionResultsy InkInputConfiguration.IsPenHapticFeedbackEnabled no están disponibles.
  • InkToolbarRulerButton.Ruler y el InkToolbar.IsRulerButtonCheckedChanged evento no están disponibles. UWP dejó de usar InkToolbarRulerButton en favor de InkToolbarStencilButton, así que use el botón de plantilla y el evento InkToolbar.IsStencilButtonCheckedChanged en su lugar.

SDK de Aplicaciones para Windows 2.4.1-experimental agregó API de borrado, como InkToolbarEraserKind y InkToolbarEraserButton.SelectedEraser, que 2.5.4-experimental eliminó. Nunca formaron parte de UWP, por lo que no los agregues al código migrado. Para obtener la lista completa, consulte Cambios de la versión 2.4.1-experimental.

Dado que los tipos como InkPresenter y InkStrokeContainer existen en ambos espacios de nombres, importar ambos Microsoft.UI.Xaml.Controls y Windows.UI.Input.Inking provoca el error CS0104 cuando se usan esos nombres. Importe Microsoft.UI.Xaml.Controlsy agregue directivas de alias para los Windows.UI.Input.Inking tipos que use:

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

InkStrokeContainer.SaveAsync escribe en un IOutputStream, y LoadAsync lee de un IInputStream. Para usar System.IO flujos de archivo, conviértelos con AsOutputStream y AsInputStream. El archivo necesita using System; para esperar estos métodos de Windows Runtime, junto con using System.IO; y 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);
}

Puede seguir conectando la barra de herramientas al lienzo con InkToolbar.TargetInkCanvas, o establecer TargetInkPresenter para conectarla directamente a un InkPresenter. Para agregar sus propias herramientas a la barra de herramientas, use InkToolbarCustomToolButton y InkToolbarCustomToggleButton, como se muestra en Personalizar la barra de herramientas de entrada de lápiz. Antes de migrar, revise las limitaciones conocidas, como los problemas notificados con la regla y las plantillas de transportador.

Si la aplicación debe usar una versión estable, no hay ningún control de entrada manuscrita integrado al que migrar. Representar trazos con Win2D y controlar la entrada de puntero usted mismo, o usar una biblioteca de entrada manuscrita de terceros. Para reemplazar InkToolbar, use un CommandBar con AppBarToggleButton elementos.

Win2D

El nombre del paquete Win2D cambió, pero la superficie de API es idéntica:

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

Todas las Microsoft.Graphics.Canvas.* API (CanvasDevice, CanvasBitmap, CanvasRenderTarget, DrawInk) funcionan de la misma manera. Solo la referencia del paquete NuGet necesita actualizarse.

Impresión

La impresión de UWP utiliza PrintManager.GetForCurrentView(). WinUI 3 requiere interoperabilidad con el identificador de ventana:

// 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);

Las PrintDocument API de representación (Paginate, GetPreviewPage, AddPages) no se modifican.

Importante

Si omites el identificador de ventana, PrintManagerInterop.GetForWindow lanza un COMException. Este es el mismo patrón de interoperabilidad que FileOpenPicker: cualquier API que usaba GetForCurrentView() en UWP necesita un identificador de ventana en WinUI 3.

Mensaje de inicio

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.

Cambios en el archivo del proyecto

Reemplazar el marco de destino de 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>

Agregue el paquete SDK de Aplicaciones para Windows:

dotnet add package Microsoft.WindowsAppSDK