🚀 Quality resource sharing 🚀
Learning route guidance (click to unlock) | Knowledge orientation | Crowd positioning |
---|---|---|
🧡 Python actual WeChat ordering applet 🧡 | Progressive class | This course is a perfect combination of python flask+WeChat applet, from project construction to Tencent cloud deployment and online, to build a full stack meal ordering system. |
💛 Python quantitative trading practice 💛 | beginner | Take you hand in hand to build a quantitative trading system that is easy to expand, safer and more efficient |
This article is WinUI 3 Footing Record Part of the series released on GitHub@Scighost/WinUI3Keng , the code in this article is also in this warehouse, and the GitHub shall prevail in case of any conflict.
The entry of WinUI 3 application is similar to that of UWP. It is also a class inherited from Application. The slight difference is that there are not as many startup methods for rewriting as UWP, and only one OnLaunched can be rewritten. The content in OnLaunched is very simple. It is to construct a main window and activate it.
// App.xaml.cs public partial class App : Application { public App() { this.InitializeComponent(); } protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args) { // Construct a main window and activate it m_window = new MainWindow(); m_window.Activate(); } private Window m_window; }
This article will focus on the main window, and introduce the setting of mica or acrylic background, adjusting the window position and size, and customizing the title bar.
Set Mica or Acrylic Background
You can set the background material in Official documents There are very detailed methods in, and I will not introduce them too much. In this article, I use my personal encapsulation method, The source code is here.
// MainWindow.xaml.cs using Scighost.WinUILib.Helpers; private SystemBackdropHelper backdropHelper; public MainWindow() { this.InitializeComponent(); backdropHelper = new SystemBackdropHelper(this); // Set mica background. If it is not supported, set it as acrylic background backdropHelper.TrySetMica(fallbackToAcrylic: true); }
Resize Window Position
What is the first thing to do after creating a window?
Yes, it is to obtain the window handle (HWND). This process is very different from WPF/UWP, but very similar to Win32. Because the window class Microsoft. UI. Xaml There are almost no methods related to window state in Window, but the so-called HWND advanced encapsulation class Microsoft.UI.Windowing AppWindow also contains limited methods, which can only be obtained through window handles. In contrast, WPF encapsulates almost all the common operations on windows, which shows that WPF is superior in development experience.
// MainWindow.xaml.cs // Namespace True ™ chaos using Microsoft.UI; using Microsoft.UI.Windowing; using Microsoft.UI.Xaml; using WinRT.Interop; private IntPtr hwnd; private AppWindow appWindow; public MainWindow() { this.InitializeComponent(); hwnd = WindowNative.GetWindowHandle(this); WindowId id = Win32Interop.GetWindowIdFromWindow(hwnd); appWindow = AppWindow.GetFromWindowId(id); }
WinUI 3 does not automatically save the window size and location. This function needs to be implemented by itself. There is no method to maximize the window, and Win32 Api needs to be called.
// MainWindow.xaml.cs using Vanara.PInvoke; using Windows.Graphics; // window maximizing User32.ShowWindow(hwnd, ShowWindowCommand.SW_SHOWMAXIMIZED); // Adjust window position and size in screen pixels appWindow.MoveAndResize(new RectInt32(\_X: 560, \_Y: 280, \_Width: 800, \_Height: 600));
The general process is to save the location and size when the window is closed, and load the saved settings when starting. Here we use Setting function of application package , but the data types that the Api can store do not include Windows.Graphics.RectInt32. Make some adjustments to the data model.
Note: The setting function of application package cannot be used for non packaged applications
// MainWindow.xaml.cs using Microsoft.UI.Windowing; using Vanara.PInvoke; using Windows.Graphics; using Windows.Storage; using System.Runtime.InteropServices; public sealed partial class MainWindow : Window { ...... public MainWindow() { ...... // Initialize window size and position this.Closed += MainWindow_Closed; if (ApplicationData.Current.LocalSettings.Values["IsMainWindowMaximum"] is true) { // Maximize User32.ShowWindow(hwnd, ShowWindowCommand.SW_SHOWMAXIMIZED); } else if (ApplicationData.Current.LocalSettings.Values["MainWindowRect"] is ulong value) { var rect = new WindowRect(value); // Screen area var area = DisplayArea.GetFromWindowId(windowId: id, DisplayAreaFallback.Primary); // If the window is within the screen if (rect.Left > 0 && rect.Top > 0 && rect.Right < area.WorkArea.Width && rect.Bottom < area.WorkArea.Height) { appWindow.MoveAndResize(rect.ToRectInt32()); } } } private void MainWindow\_Closed(object sender, WindowEventArgs args) { // Save Window State var wpl = new User32.WINDOWPLACEMENT(); if (User32.GetWindowPlacement(hwnd, ref wpl)) { ApplicationData.Current.LocalSettings.Values["IsMainWindowMaximum"] = wpl.showCmd == ShowWindowCommand.SW_MAXIMIZE; var p = appWindow.Position; var s = appWindow.Size; var rect = new WindowRect(p.X, p.Y, s.Width, s.Height); ApplicationData.Current.LocalSettings.Values["MainWindowRect"] = rect.Value; } } /// ///RectInt32 and ulong convert each other /// [StructLayout(LayoutKind.Explicit)] private struct WindowRect { [FieldOffset(0)] public short X; [FieldOffset(2)] public short Y; [FieldOffset(4)] public short Width; [FieldOffset(6)] public short Height; [FieldOffset(0)] public ulong Value; public int Left => X; public int Top => Y; public int Right => X + Width; public int Bottom => Y + Height; public WindowRect(int x, int y, int width, int height) { X = (short)x; Y = (short)y; Width = (short)width; Height = (short)height; } public WindowRect(ulong value) { Value = value; } public RectInt32 ToRectInt32() { return new RectInt32(X, Y, Width, Height); } } }
So far, all functions of window state have been completed.
Customize Title Block
Customizing the title bar is something that every application should do. After all, a lonely white stripe suddenly appears at the top of the window, which is a bit disappointing.
WinUI 3 provides two methods to customize the title bar. For more details about these two methods, see file.
Use the properties provided in Window
By setting Window ExtendsContentIntoTitleBar=true extends the content of the client area to the title bar. The usage is simple. Then you need to call SetTitleBar(UIElement titleBar) to tell the system the range of drainable areas. The titleBar here is a control defined in an xaml file. After calling this Api, the part covered by the control will be set as a drainable area.
// MainWindow.xaml.cs using Microsoft.UI.Xaml; this.ExtendsContentIntoTitleBar = true; this.SetTitleBar(AppTitleBar);
<Grid> <Border x:Name="AppTitleBar" Height="48" VerticalAlignment="Top"> <TextBlock VerticalAlignment="Center" Text="WinUI Desktop" /> Border> Grid>
<StaticResource x:Key="WindowCaptionBackground" ResourceKey="ControlFillColorTransparentBrush" /> <StaticResource x:Key="WindowCaptionBackgroundDisabled" ResourceKey="ControlFillColorTransparentBrush" />
However, there are two problems with this method:
First, the draggable area set by SetTitleBar must be a complete area, and all controls within the range cannot be clicked again. Therefore, this method cannot realize the function of embedding a search box in the title bar of Microsoft Store.
To find out, use Spy++to view the properties of the window, as shown in the following figure.
The WinUI Desktop here is the main window, and there are two sub windows inside. The DRAG can be seen from the name_ BAR_ WINDOW_ CLASS is related to the drag function. Check its size and position. It is exactly the range set by SetTitleBar (system zoom rate is 150%). The second DesktopChildSiteBridge is Xaml Island that hosts UI content.
It can be concluded that the mouse operation on the custom title block will be transferred to DRAG_BAR_WINDOW_CLASS, while DesktopChildSiteBridge will not receive related messages, so all controls in this area cannot be clicked. This principle also determines that the draggable area can only be a rectangle. The use of Spy++to view the contents of window messages also proves this (figure out).
Second, the operation cannot be canceled after clicking the three buttons in the upper right corner. Even if you move the mouse away, the operation will be triggered when you release the button. See this for specific behavior issue.
Using AppWindowTitleBar
AppwindowTitleBar is a method on Windows 11. Compared with the former, it can set multiple draggable areas, which makes it possible to interoperate the controls of the title bar. If you do not actively set a draggable area, the original title block area will automatically become a draggable area.
// MainWindow.xaml.cs // Check if this method is supported if (AppWindowTitleBar.IsCustomizationSupported()) { // titleBar is null when not supported titleBar = appWindow.TitleBar; titleBar.ExtendsContentIntoTitleBar = true; // The background color of the title bar keys is set to transparent titleBar.ButtonBackgroundColor = Colors.Transparent; titleBar.ButtonInactiveBackgroundColor = Colors.Transparent; }
When manually setting the draggable area, be sure to pay attention to the system zoom rate. The area set by AppwindowTitleBar is in pixels, and the controls in the UI will be more affected by the zoom rate. You need to manually multiply the zoom rate when setting the draggable area.
// MainWindow.xaml.cs using Windows.Graphics; using Vanara.PInvoke; // Get system zoom rate var scale = (float)User32.GetDpiForWindow(hwnd) / 96; // 48 This value is the height of the application title bar. It is not unique. It depends on your own UI design titleBar.SetDragRectangles(new RectInt32[] { new RectInt32(0, 0, 10000, (int)(48 * scale)) });
Why set the width of the draggable area to 10000? If the setting is small, the part not covered on the right side of the title bar cannot be dragged. If the setting is large, the three buttons on the upper right corner will not be affected (no one's display pixel width is greater than 10000).
Modify draggable area
In many cases, you need to modify the draggable area. The most common thing is that when the window width decreases, the menu buttons of NavigationView will run up to the top. In the following figure, three horizontal line buttons are used.
If you are using Window SetTitleBar, it will be very simple to modify the draggable area. You can directly modify the boundary size of the AppTitleBar control without considering the impact of the system zoom rate.
AppTitleBar.Margin = new Thickness(96, 0, 0, 0);
If you are using AppWindowTitleBar SetDragRectangles, then there is a problem. Look at the picture below. If you first set the range of the orange box as a draggable area, and then set the range of the blue box as a draggable area, what will happen?
The answer is that blue boxes can be dragged, but green boxes can neither be dragged nor clicked. This is a Bug in the v1.1 version of the WindowsApp SDK. This Bug basically eliminates the possibility of modifying the control layout on the title bar. You can call AppWindowTitleBar ResetToDefault() solves this problem, but the system title bar will suddenly appear and then disappear, which will greatly affect the experience. For more details about this Bug, you can view the developers of iQIYI Preview kingcean Proposed issue In the issue, it is mentioned that v1.2 preview 1 has solved the Bug. My test has indeed solved it.
New features of v1.2 Preview 1
It is mentioned in the update content of v1.2 preview 1 that AppWindowTitleBar has been supported in Windows 10. In my test, ExtendsContentIntoTitleBar has been available and successfully extended the client area to the title bar. However, whether or not SetDragRectangles is called, the window cannot be dragged (refer to this issue ), let's wait for the follow-up repair.
summary
WinUI 3 is much more troublesome than WPF/UWP in window operations. Many common operations are not encapsulated, such as maximum and minimum, hidden windows, etc. Because of the different design ideas on windows, many functions need to be implemented through window handles, which should be hidden. This is why I want to write down the knowledge about Win32 windows in the foreword.
Microsoft has reason to say that what framework I developed is the latest generation of framework; What do you want me to package? It's an old Win32. Oh, thank God. What is the current level of WinUI 3? It is so troublesome to change a window. Can it work? No fire, I don't have this ability, you know. With WPF Zhuyu in the front, what can we compare with others? If we don't get cut off, we will be successful.