Eseguire la migrazione di un'app UWP a WinUI 3

La piattaforma UWP non è più in fase di sviluppo attivo. WinUI 3 e il SDK per app di Windows sono i suoi successori e gli strumenti di intelligenza artificiale possono automatizzare la maggior parte della migrazione. La sfida principale è che i modelli di intelligenza artificiale sono stati sottoposti a training su anni di esempi UWP, quindi senza indicazioni riproducono i modelli da cui si sta tentando di allontanarsi. Questa pagina fornisce all'agente il contesto necessario per farlo correttamente.

Installare il plug-in dell'agente WinUI

La winui-uwp-migration competenza gestisce automaticamente le sostituzioni comuni:

gh copilot plugin install winui@awesome-copilot

Per informazioni dettagliate, vedere il plug-in dell'agente WinUI .

Tabella di sostituzione API

Le tabelle seguenti riepilogano le sostituzioni API più comuni. Per la mappatura completa e dettagliata, inclusi membri, proprietà e API meno comuni, consulta Mappatura delle API e delle librerie UWP a SDK per app di Windows.

Important

x:Bind è impostato per impostazione predefinita su OneTime. A differenza di {Binding} (il cui valore predefinito è OneWay), x:Bind viene valutato una sola volta, a meno che non si specifichi Mode=OneWay o Mode=TwoWay. Durante la migrazione, verifica tutte le espressioni x:Bind associate a proprietà che cambiano in fase di esecuzione: l'assenza di Mode=OneWay causa bug del tipo "l'interfaccia utente non si aggiorna", invisibili in fase di compilazione.

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

Gestione dei thread

UWP WinUI 3
CoreDispatcher DispatcherQueue
Dispatcher.RunAsync(...) DispatcherQueue.TryEnqueue(...)
CoreApplication.MainView.CoreWindow.Dispatcher this.DispatcherQueue (da un Window o Page)

Windowing

UWP WinUI 3
ApplicationView AppWindow
ApplicationView.GetForCurrentView() AppWindow.GetFromWindowId(...)
ApplicationViewTitleBar AppWindowTitleBar
CoreWindow Microsoft.UI.Xaml.Window
SystemNavigationManager Pulsante Indietro tramite AppWindowTitleBar

Dialoghi e selezione

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

Important

I selettori richiedono InitializeWithWindow prima di invocare PickSingleFileAsync (o simile):

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

ContentDialog richiede XamlRoot (non InitializeWithWindow):

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

Notifiche

UWP WinUI 3
Windows.UI.Notifications.ToastNotificationManager Microsoft.Windows.AppNotifications.AppNotificationManager
Windows.UI.Notifications.BadgeUpdateManager Microsoft.Windows.BadgeNotifications.BadgeNotificationManager
Windows.UI.Notifications.TileUpdateManager I riquadri sono deprecati: usare notifiche o widget

Rete e HTTP

UWP WinUI 3 (scelta consigliata)
Windows.Web.Http.HttpClient System.Net.Http.HttpClient (portabile, nessuna dipendenza WinRT)
Windows.Web.Syndication.SyndicationClient System.ServiceModel.Syndication.SyndicationFeed + HttpClient
Windows.Web.AtomPub.AtomPubClient System.ServiceModel.Syndication o HTTP diretto

Note

Le API HTTP WinRT (Windows.Web.Http) funzionano ancora nelle app WinUI 3 in pacchetto, ma gli equivalenti .NET sono consigliati per la portabilità, il debug più semplice e il supporto dell'ecosistema più ampio (middleware, DI, mocking).

UWP WinUI 3
Frame.Navigate(typeof(MyPage)) Frame.Navigate(typeof(MyPage)) — invariato
SystemNavigationManager.BackRequested Gestire tramite NavigationView o AppWindow
Windows.UI.Core.Preview.SystemNavigationManagerPreview AppWindow.Closing evento

Note

Navigazione hamburger personalizzata (SplitView + NavMenuListView): Molti esempi UWP implementavano la navigazione tramite un elemento AppShell.xaml con SplitView e un controllo NavMenuListView sviluppato manualmente (~500+ righe). In WinUI 3 sostituire questo modello intero con NavigationView, che fornisce la stessa esperienza utente con accessibilità predefinita, comportamento reattivo e supporto del pulsante indietro. Si tratta in genere di una riduzione del codice di 80%.

Modelli MVVM

UWP (implementazioni personalizzate comuni) WinUI 3 (scelta consigliata)
Personalizzato BindableBase / ObservableObject CommunityToolkit.Mvvm.ComponentModel.ObservableObject
Personalizzato DelegateCommand / RelayCommand CommunityToolkit.Mvvm.Input.RelayCommand
Manuale SetProperty + OnPropertyChanged [ObservableProperty] generatore di codice sorgente
INavigationService personalizzato Integrato Frame.Navigate + NavigationView

Tip

Il pacchetto NuGet CommunityToolkit.Mvvm è la base MVVM consigliata per le app WinUI 3. Sostituisce le classi base scritte manualmente con equivalenti testati generati dal codice sorgente, eliminando centinaia di righe di codice boilerplate.

dotnet add package CommunityToolkit.Mvvm

Ciclo di vita dell'app

UWP WinUI 3
Application.Current.Suspending Microsoft.Windows.AppLifecycle (richiede modifiche dell'architettura - vedere la nota)
Application.Current.Resuming AppInstance.GetCurrent().Activated (vedere la nota)
BackgroundTaskBuilder Le attività in background di SDK per app di Windows

Note

La migrazione del ciclo di vita dell'app WinUI 3 non è un semplice scambio di nomi API. Il SDK per app di Windows usa un modello di attivazione e sospensione diverso. Trattare il codice relativo al ciclo di vita come qualcosa che richiede una riscrittura dedicata anziché una sostituzione automatica. Per il modello completo, vedere la documentazione SDK per app di Windows ciclo di vita.

Impostazioni e archiviazione

UWP WinUI 3 (in pacchetto) WinUI 3 (senza pacchetto)
ApplicationData.Current.LocalSettings Invariato ❌ Genera : nessuna identità del pacchetto
ApplicationData.Current.LocalFolder Invariato ❌ Genera : nessuna identità del pacchetto
Windows.Storage.KnownFolders Invariato ❌ Genera : nessuna identità del pacchetto

Avvertimento

Le app senza pacchetto non possono usare ApplicationData.Current: genera un errore in fase di esecuzione perché non esiste alcuna identità del pacchetto. Usare invece API di file .NET standard:

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 la tua app UWP usava DataContractSerializer con [DataMember]/[IgnoreDataMember], valuta la possibilità di passare a System.Text.Json (più veloce, più leggero, con supporto per la generazione del codice sorgente). La mappatura degli attributi è:

  • [DataMember] [JsonPropertyName("name")] → (o usare direttamente i nomi delle proprietà)
  • [IgnoreDataMember] → [JsonIgnore]
  • [DataContract] → Nessuna necessità equivalente (System.Text.Json serializza le proprietà pubbliche per impostazione predefinita)

API che non cambiano

Windows.Devices.*, Windows.Media.*, Windows.UI.ViewManagement.UISettings, Windows.UI.Color e la maggior parte delle API WinRT all'esterno dello spazio dei nomi XAML rimane invariata.

Controlli senza un equivalente diretto

Alcuni controlli UWP non esistono in WinUI 3. Scegliere una sostituzione in base al proprio scenario:

Controllo UWP Sostituzione di WinUI 3 Notes
Pivot TabView, NavigationView (modalità superiore) o RadioButtons + visibilità Per 2-3 schede fisse, RadioButtons con la commutazione della visibilità è la soluzione più semplice. Per le schede dinamiche/chiudibili, usare TabView.
RadialController Interoperabilità WinRT con handle di finestra RadialController.CreateForCurrentView() non ha equivalenti diretti. Uso di RadialControllerInterop con GetForWindow(hwnd).
SystemNavigationManager pulsante Indietro personalizzato o NavigationView.IsBackEnabled SystemNavigationManager.GetForCurrentView() non esiste. Aggiungi un pulsante Indietro personalizzato o usa il pulsante Indietro integrato di NavigationView.

input penna, Win2D e stampa

Questi sottosistemi richiedono passaggi di migrazione specifici oltre le modifiche dello spazio dei nomi.

Windows Ink

WinUI include InkCanvas, InkToolbar, e InkPresenter come API sperimentali nelle release sperimentali di SDK per app di Windows. Le versioni stabili non le includono. Per la configurazione, la personalizzazione della barra degli strumenti e le limitazioni note, vedi Controlli di input penna per le app WinUI.

Nelle versioni sperimentali, i controlli e i tipi che elaborano l'input penna digitale sono in Microsoft.UI.Xaml.Controls. I tratti e gli attributi di disegno rimangono in Windows.UI.Input.Inking:

UWP WinUI 3 (versioni sperimentali)
Windows.UI.Xaml.Controls.InkCanvas, InkToolbare gli altri InkToolbar* tipi Microsoft.UI.Xaml.Controls, stessi nomi di tipo. Alcuni membri differiscono.
Windows.UI.Input.Inking.InkPresenter, InkStrokeContainer, InkUnprocessedInput, InkSynchronizer, InkInputConfiguration, InkInputProcessingConfiguration, InkInputRightDragAction, InkInputProcessingMode, InkStrokesCollectedEventArgs, InkHighContrastAdjustment, InkStrokeInput, InkStrokesErasedEventArgs Microsoft.UI.Xaml.Controls, stessi nomi di tipo. Alcuni membri differiscono.
Windows.UI.Input.Inking.InkStroke, InkDrawingAttributes, InkPoint, InkStrokeBuilder, InkPersistenceFormat, PenTipShape Nessuna modifica
Windows.UI.Core.CoreInputDeviceTypes Nessuna modifica

Ogni tipo UWP nelle prime due righe ha una controparte con lo stesso nome, ma SDK per app di Windows 2.5.4-experimental non include tutti i relativi membri:

  • InkStrokeContainer non ha un costruttore pubblico ed InkPresenter.StrokeContainer è di sola lettura. Per passare da un set di tratti all'altro, salvare ogni set con SaveAsync e ripristinarlo con LoadAsync, che sostituisce i tratti correnti.
  • SaveAsync e LoadAsync restituiscono IAsyncAction, quindi non segnalano lo stato di avanzamento e SaveAsync non restituisce il numero di byte scritti.
  • InkStrokeContainer.GetRecognitionResults, InkStrokeContainer.UpdateRecognitionResultse InkInputConfiguration.IsPenHapticFeedbackEnabled non sono disponibili.
  • InkToolbarRulerButton.Ruler e l'evento InkToolbar.IsRulerButtonCheckedChanged non sono disponibili. In UWP, InkToolbarRulerButton è deprecato a favore di InkToolbarStencilButton, quindi usa il pulsante stencil e l'evento InkToolbar.IsStencilButtonCheckedChanged invece.

SDK per app di Windows 2.4.1-experimental ha aggiunto API per la gomma sperimentali, ad esempio InkToolbarEraserKind e InkToolbarEraserButton.SelectedEraser, che la versione 2.5.4-experimental ha rimosso. Non hanno mai fatto parte di UWP, quindi non aggiungerli al codice migrato. Per l'elenco completo, vedere Modifiche dalla versione 2.4.1-sperimentale.

Poiché i tipi come InkPresenter e InkStrokeContainer sono presenti in entrambi gli spazi dei nomi, l'importazione di entrambi Microsoft.UI.Xaml.Controls e Windows.UI.Input.Inking causa l'errore CS0104 quando si usano tali nomi. Importare Microsoft.UI.Xaml.Controlse aggiungere direttive alias per i Windows.UI.Input.Inking tipi usati:

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

InkStrokeContainer.SaveAsync scrive in un IOutputStream e LoadAsync legge da un IInputStream. Per usare System.IO i flussi di file, convertirli con AsOutputStream e AsInputStream. Il file deve usare using System; per attendere questi metodi di Windows Runtime, insieme a 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);
}

È possibile mantenere la connessione della barra degli strumenti all'area di disegno con InkToolbar.TargetInkCanvas o impostare TargetInkPresenter per connetterla direttamente a un InkPresenter. Per aggiungere strumenti personalizzati alla barra degli strumenti, usare InkToolbarCustomToolButton e InkToolbarCustomToggleButton, come illustrato in Personalizzare la barra degli strumenti input penna. Prima di eseguire la migrazione, esaminare le limitazioni note, ad esempio i problemi segnalati con gli stencil righello e goniometro.

Se l'app deve usare una versione stabile, non è disponibile alcun controllo penna integrato a cui eseguire la migrazione. Eseguire il rendering dei tratti con Win2D e gestire manualmente l'input del puntatore oppure usare una libreria di input penna di terze parti. Per sostituire InkToolbar, usare un oggetto CommandBar con AppBarToggleButton elementi.

Win2D

Il nome del pacchetto Win2D è stato modificato ma la superficie dell'API è identica:

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

Tutte le Microsoft.Graphics.Canvas.* API (CanvasDevice, CanvasBitmap, CanvasRenderTarget, DrawInk) funzionano allo stesso modo. È necessario aggiornare solo il riferimento al pacchetto NuGet.

Stampa

La stampa UWP usa PrintManager.GetForCurrentView(). WinUI 3 richiede l'interoperabilità con l'handle di finestra:

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

Le PrintDocument API di rendering (Paginate, GetPreviewPage, AddPages) sono invariate.

Important

Se si omette l'handle di finestra, PrintManagerInterop.GetForWindow genera un'eccezione COMException. Questo è lo stesso modello di interoperabilità di FileOpenPicker : qualsiasi API usata GetForCurrentView() in UWP richiede un handle di finestra in WinUI 3.

Prompt di avvio

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.

Modifiche ai file di progetto

Sostituire il framework di destinazione 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>

Aggiungere il pacchetto SDK per app di Windows:

dotnet add package Microsoft.WindowsAppSDK