Guide de Migration WinUI 3
Utilise cette compétence lors de la migration d'applications UWP vers WinUI 3 / Windows App SDK, ou pour vérifier que le code généré utilise les bonnes API WinUI 3 au lieu des anciens patterns UWP.
Changements de Namespace
Tous les namespaces Windows.UI.Xaml.* se déplacent vers Microsoft.UI.Xaml.* :
| Namespace UWP |
Namespace 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.Xaml.Input |
Microsoft.UI.Xaml.Input |
Windows.UI.Xaml.Data |
Microsoft.UI.Xaml.Data |
Windows.UI.Xaml.Navigation |
Microsoft.UI.Xaml.Navigation |
Windows.UI.Xaml.Shapes |
Microsoft.UI.Xaml.Shapes |
Windows.UI.Composition |
Microsoft.UI.Composition |
Windows.UI.Input |
Microsoft.UI.Input |
Windows.UI.Colors |
Microsoft.UI.Colors |
Windows.UI.Text |
Microsoft.UI.Text |
Windows.UI.Core |
Microsoft.UI.Dispatching (pour le dispatcher) |
Top 3 des Erreurs les Plus Courantes de Copilot
1. ContentDialog sans XamlRoot
// ❌ FAUX — Lève InvalidOperationException dans WinUI 3
var dialog = new ContentDialog
{
Title = "Error",
Content = "Something went wrong.",
CloseButtonText = "OK"
};
await dialog.ShowAsync();
// ✅ CORRECT — Définir XamlRoot avant d'afficher
var dialog = new ContentDialog
{
Title = "Error",
Content = "Something went wrong.",
CloseButtonText = "OK",
XamlRoot = this.Content.XamlRoot // Requis dans WinUI 3
};
await dialog.ShowAsync();
2. MessageDialog au lieu de ContentDialog
// ❌ FAUX — API UWP, non disponible dans le desktop WinUI 3
var dialog = new Windows.UI.Popups.MessageDialog("Are you sure?", "Confirm");
await dialog.ShowAsync();
// ✅ CORRECT — Utiliser ContentDialog
var dialog = new ContentDialog
{
Title = "Confirm",
Content = "Are you sure?",
PrimaryButtonText = "Yes",
CloseButtonText = "No",
XamlRoot = this.Content.XamlRoot
};
var result = await dialog.ShowAsync();
if (result == ContentDialogResult.Primary)
{
// Utilisateur confirmé
}
3. CoreDispatcher au lieu de DispatcherQueue
// ❌ FAUX — CoreDispatcher n'existe pas dans WinUI 3
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
StatusText.Text = "Done";
});
// ✅ CORRECT — Utiliser DispatcherQueue
DispatcherQueue.TryEnqueue(() =>
{
StatusText.Text = "Done";
});
// Avec priorité :
DispatcherQueue.TryEnqueue(DispatcherQueuePriority.High, () =>
{
ProgressBar.Value = 100;
});
Migration de Windowing
Référence de Fenêtre
// ❌ FAUX — Window.Current n'existe pas dans WinUI 3
var currentWindow = Window.Current;
// ✅ CORRECT — Utiliser une propriété statique dans App
public partial class App : Application
{
public static Window MainWindow { get; private set; }
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
MainWindow = new MainWindow();
MainWindow.Activate();
}
}
// Accéder partout : App.MainWindow
Gestion de Fenêtre
| API UWP |
API WinUI 3 |
ApplicationView.TryResizeView() |
AppWindow.Resize() |
AppWindow.TryCreateAsync() |
AppWindow.Create() |
AppWindow.TryShowAsync() |
AppWindow.Show() |
AppWindow.TryConsolidateAsync() |
AppWindow.Destroy() |
AppWindow.RequestMoveXxx() |
AppWindow.Move() |
AppWindow.GetPlacement() |
Propriété AppWindow.Position |
AppWindow.RequestPresentation() |
AppWindow.SetPresenter() |
Barre de Titre
| API UWP |
API WinUI 3 |
CoreApplicationViewTitleBar |
AppWindowTitleBar |
CoreApplicationView.TitleBar.ExtendViewIntoTitleBar |
AppWindow.TitleBar.ExtendsContentIntoTitleBar |
Migration des Dialogues et Sélecteurs
Sélecteurs de Fichiers/Dossiers
// ❌ FAUX — Style UWP, pas de handle de fenêtre
var picker = new FileOpenPicker();
picker.FileTypeFilter.Add(".txt");
var file = await picker.PickSingleFileAsync();
// ✅ CORRECT — Initialiser avec le handle de fenêtre
var picker = new FileOpenPicker();
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(App.MainWindow);
WinRT.Interop.InitializeWithWindow.Initialize(picker, hwnd);
picker.FileTypeFilter.Add(".txt");
var file = await picker.PickSingleFileAsync();
Migration du Threading
| Pattern UWP |
Équivalent WinUI 3 |
CoreDispatcher.RunAsync(priority, callback) |
DispatcherQueue.TryEnqueue(priority, callback) |
Dispatcher.HasThreadAccess |
DispatcherQueue.HasThreadAccess |
CoreDispatcher.ProcessEvents() |
Pas d'équivalent — restructurer le code async |
CoreWindow.GetForCurrentThread() |
Non disponible — utiliser DispatcherQueue.GetForCurrentThread() |
Différence clé : UWP utilise ASTA (Application STA) avec blocage de réentrance intégré. WinUI 3 utilise STA standard sans cette protection. Attention aux problèmes de réentrance quand le code async traite les messages.
Migration des Tâches de Fond
// ❌ FAUX — IBackgroundTask UWP
public sealed class MyTask : IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance) { }
}
// ✅ CORRECT — Windows App SDK AppLifecycle
using Microsoft.Windows.AppLifecycle;
// S'inscrire pour l'activation
var args = AppInstance.GetCurrent().GetActivatedEventArgs();
if (args.Kind == ExtendedActivationKind.AppNotification)
{
// Gérer l'activation de fond
}
Migration des Paramètres d'Application
| Scénario |
Application Empaquetée |
Application Non Empaquetée |
| Paramètres simples |
ApplicationData.Current.LocalSettings |
Fichier JSON dans LocalApplicationData |
| Stockage de fichiers local |
ApplicationData.Current.LocalFolder |
Environment.GetFolderPath(SpecialFolder.LocalApplicationData) |
Remplacements de GetForCurrentView()
Tous les patterns GetForCurrentView() sont indisponibles dans les applications desktop WinUI 3 :
| API UWP |
Remplacement WinUI 3 |
UIViewSettings.GetForCurrentView() |
Utiliser les propriétés AppWindow |
ApplicationView.GetForCurrentView() |
AppWindow.GetFromWindowId(windowId) |
DisplayInformation.GetForCurrentView() |
Win32 GetDpiForWindow() ou XamlRoot.RasterizationScale |
CoreApplication.GetCurrentView() |
Non disponible — tracker les fenêtres manuellement |
SystemNavigationManager.GetForCurrentView() |
Gérer la navigation arrière dans NavigationView directement |
Migration des Tests
Les projets de test unitaire UWP ne fonctionnent pas avec WinUI 3. Tu dois migrer vers les modèles de projet de test WinUI 3.
| UWP |
WinUI 3 |
| Unit Test App (Universal Windows) |
Unit Test App (WinUI in Desktop) |
| Projet MSTest standard avec types UWP |
Doit utiliser l'application de test WinUI pour le runtime Xaml |
[TestMethod] pour tous les tests |
[TestMethod] pour la logique, [UITestMethod] pour les tests XAML/UI |
| Class Library (Universal Windows) |
Class Library (WinUI in Desktop) |
// ✅ Test unitaire WinUI 3 — utiliser [UITestMethod] pour toute interaction XAML
[UITestMethod]
public void TestMyControl()
{
var control = new MyLibrary.MyUserControl();
Assert.AreEqual(expected, control.MyProperty);
}
Clé : L'attribut [UITestMethod] indique au runner de test d'exécuter le test sur le thread UI XAML, ce qui est requis pour instancier n'importe quel type Microsoft.UI.Xaml.
Checklist de Migration
- [ ] Remplacer tous les directives using
Windows.UI.Xaml.* par Microsoft.UI.Xaml.*
- [ ] Remplacer
Windows.UI.Colors par Microsoft.UI.Colors
- [ ] Remplacer
CoreDispatcher.RunAsync par DispatcherQueue.TryEnqueue
- [ ] Remplacer
Window.Current par la propriété statique App.MainWindow
- [ ] Ajouter
XamlRoot à toutes les instances de ContentDialog
- [ ] Initialiser tous les sélecteurs avec
InitializeWithWindow.Initialize(picker, hwnd)
- [ ] Remplacer
MessageDialog par ContentDialog
- [ ] Remplacer
ApplicationView/CoreWindow par AppWindow
- [ ] Remplacer
CoreApplicationViewTitleBar par AppWindowTitleBar
- [ ] Remplacer tous les appels
GetForCurrentView() par des équivalents AppWindow
- [ ] Mettre à jour l'interop pour les gestionnaires de Partage et Impression
- [ ] Remplacer
IBackgroundTask par l'activation AppLifecycle
- [ ] Mettre à jour le fichier projet : TFM à
net10.0-windows10.0.22621.0, ajouter <UseWinUI>true</UseWinUI>
- [ ] Migrer les tests unitaires vers le projet Unit Test App (WinUI in Desktop) ; utiliser
[UITestMethod] pour les tests XAML
- [ ] Tester les configurations empaquetée et non empaquetée