master
cs 178 lines 6.29 KB
Raw
1 // Copyright (C) Microsoft Corporation. All rights reserved.
2
3 using Microsoft.UI.Xaml;
4 using Microsoft.UI.Xaml.Controls;
5 using Microsoft.UI.Xaml.Input;
6
7 using System.Diagnostics;
8
9 using Windows.System;
10
11 using System.ComponentModel;
12 using System.Runtime.CompilerServices;
13 using WslSettings.Contracts.Services;
14 using WslSettings.Services;
15 using WslSettings.ViewModels;
16
17 namespace WslSettings.Views.Settings;
18
19 public sealed partial class ShellPage : Page, INotifyPropertyChanged
20 {
21 private readonly Microsoft.UI.Dispatching.DispatcherQueue _dispatcherQueue = Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread();
22
23 public bool HasPendingChanges => App.GetService<IWslConfigService>().HasPendingChanges;
24
25 public event PropertyChangedEventHandler? PropertyChanged;
26
27 private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
28 {
29 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
30 }
31
32 private void RegisterNavigationService()
33 {
34 ViewModel.NavigationViewService.UnregisterEvents();
35 ViewModel.NavigationService.Frame = NavigationFrame;
36 ViewModel.NavigationViewService.Initialize(NavigationViewControl);
37 }
38
39 public ShellViewModel ViewModel
40 {
41 get;
42 }
43
44 public ShellPage(ShellViewModel viewModel)
45 {
46 ViewModel = viewModel;
47 InitializeComponent();
48
49 RegisterNavigationService();
50
51 // TODO: Set the title bar icon by updating /Assets/wsl.ico.
52 // A custom title bar is required for full window theme and Mica support.
53 // https://docs.microsoft.com/windows/apps/develop/title-bar?tabs=winui3#full-customization
54 App.MainWindow!.ExtendsContentIntoTitleBar = true;
55 App.MainWindow.SetTitleBar(AppTitleBar);
56 App.MainWindow.Activated += MainWindow_Activated;
57 AppTitleBarText.Text = "Settings_AppDisplayName".GetLocalized();
58 NavigationFrame.LostFocus += NavigationFrame_LostFocus;
59
60 App.GetService<IWslConfigService>().PendingChangesChanged += OnPendingChangesChanged;
61 }
62
63 private void OnPendingChangesChanged()
64 {
65 _dispatcherQueue.TryEnqueue(() =>
66 {
67 OnPropertyChanged(nameof(HasPendingChanges));
68 });
69 }
70
71 private async void ApplyChanges_Click(object sender, RoutedEventArgs e)
72 {
73 await SettingsApplyHelper.ShowApplyChangesDialogAsync(XamlRoot);
74 }
75
76 private void OnLoaded(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
77 {
78 TitleBarHelper.UpdateTitleBar(App.MainWindow!, RequestedTheme);
79
80 KeyboardAccelerators.Add(BuildKeyboardAccelerator(VirtualKey.Left, VirtualKeyModifiers.Menu));
81 KeyboardAccelerators.Add(BuildKeyboardAccelerator(VirtualKey.GoBack));
82 }
83
84 private void MainWindow_Activated(object sender, WindowActivatedEventArgs args)
85 {
86 App.AppTitlebar = AppTitleBarText as UIElement;
87 RegisterNavigationService();
88 if (ViewModel.NavigationService.Frame?.Content == null)
89 {
90 ViewModel.NavigationService.NavigateTo(typeof(ViewModels.Settings.MemAndProcViewModel).FullName!);
91 }
92 }
93
94 private void NavigationViewControl_DisplayModeChanged(NavigationView sender, NavigationViewDisplayModeChangedEventArgs args)
95 {
96 if (args.DisplayMode == NavigationViewDisplayMode.Compact || args.DisplayMode == NavigationViewDisplayMode.Minimal)
97 {
98 PaneToggleBtn.Visibility = Visibility.Visible;
99 AppTitleBar.Margin = new Thickness(48, 0, 0, 0);
100 AppTitleBarText.Margin = new Thickness(12, 0, 0, 0);
101 }
102 else
103 {
104 PaneToggleBtn.Visibility = Visibility.Collapsed;
105 AppTitleBar.Margin = new Thickness(16, 0, 0, 0);
106 AppTitleBarText.Margin = new Thickness(16, 0, 0, 0);
107 }
108 }
109
110 private void PaneToggleBtn_Click(object sender, RoutedEventArgs e)
111 {
112 NavigationViewControl.IsPaneOpen = !NavigationViewControl.IsPaneOpen;
113 }
114
115 private async void NavigationViewControl_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args)
116 {
117 switch (args.InvokedItemContainer.Tag)
118 {
119 case "LaunchWSL":
120 var wslPath = Path.Combine(AppContext.BaseDirectory, "..", "wsl.exe");
121 await Task.Run(() => Process.Start(wslPath, "--cd ~"));
122 break;
123 case "OOBE":
124 await Task.Run(() =>
125 {
126 _dispatcherQueue.TryEnqueue(() =>
127 {
128 App.GetService<IWindowService>().CreateOrGetWindow(IWindowService.WindowId.OOBEWindow).Activate();
129 });
130 });
131 break;
132 default:
133 break;
134 }
135 }
136
137 private static KeyboardAccelerator BuildKeyboardAccelerator(VirtualKey key, VirtualKeyModifiers? modifiers = null)
138 {
139 var keyboardAccelerator = new KeyboardAccelerator() { Key = key };
140
141 if (modifiers.HasValue)
142 {
143 keyboardAccelerator.Modifiers = modifiers.Value;
144 }
145
146 keyboardAccelerator.Invoked += OnKeyboardAcceleratorInvoked;
147
148 return keyboardAccelerator;
149 }
150
151 private static void OnKeyboardAcceleratorInvoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args)
152 {
153 var navigationService = App.GetService<INavigationService>();
154
155 var result = navigationService.GoBack();
156
157 args.Handled = result;
158 }
159
160 private void NavigationFrame_LostFocus(object sender, RoutedEventArgs e)
161 {
162 DispatcherQueue.TryEnqueue(() =>
163 {
164 var focused = FocusManager.GetFocusedElement(NavigationViewControl.XamlRoot);
165
166 // If focus is transferred to the selected page itself, do nothing
167 if (focused is not NavigationViewItem && focused is not NavigationView)
168 {
169 return;
170 }
171
172 // Restore focus to the selected navigation item
173 var selected = NavigationViewControl.SelectedItem;
174 var container = NavigationViewControl.ContainerFromMenuItem(selected) as Control;
175 container?.Focus(FocusState.Keyboard);
176 });
177 }
178 }