This article documents my experience in migrating a small WPF application to the UNO framework for support on the UOS(统信).
Before I begin, let me explain my requirements. I currently have a small WPF application that I need to run on both the UnionTech OS and Windows.
As we all know, there are many multi-platform development frameworks available in the current dotnet system. This time, I decided to try developing with the UNO/MAUI approach. The overall technical architecture is shown in the diagram below.
As shown in the diagram, I still use the WPF framework on Windows. However, this time the WPF framework is used as the underlying framework. Most of the business code will not directly touch the WPF framework, only some platform compatibility adaptation code will. The rest of the business code will indirectly use the WPF framework through the UNO and MAUI frameworks. On the UOS, the GTK application framework is used. Similarly, only platform compatibility adaptation code will touch the GTK application framework, and most business code will not directly interact with it.
The overall rendering layer uses SKIA to ensure consistent rendering effects across multiple platforms.
Daily Development
When creating a new project, remember to check the Windows project option. This will generate a WinUI3 project. When writing code, choose the WinUI 3 project to get XAML code intelligent prompts. When debugging, prioritize using the WinUI 3 project to debug the interface layout. You can directly use Visual Studio’s hot reload support for WinUI 3, which works better.
I recommend also adding the Skia.WPF and Skia.GTK projects. GTK can run on both Windows and Linux systems, but GTK may have some strange issues on Windows. In this case, switch to Skia.WPF. After all, those really released on the Windows platform won’t be so desperate to use GTK as the underlying layer.
Text
Flickering Black Screen on UOS
This is an OpenGL issue. For the fix, please see https://github.com/unoplatform/uno/issues/13530.
Chinese Text Garbled
Chinese text garbled is due to the incorrect loading of Chinese fonts. This problem also applies to languages such as Korean or Japanese. UOS has the Source Han Sans font by default, and GTK will automatically roll back the font. All you need to do is set the application to use Microsoft YaHei. Setting it to Microsoft YaHei will allow the application to display normal sans-serif fonts on both Windows and UOS systems.
The setting method is as follows:
Remember to use the Microsoft YaHei UI
font on the interface, the font with UI
. Otherwise, you will see some strange font layouts.
Addition: Uno with Wpf Chinese code display messy code · Issue #6973 · unoplatform/uno
TextBox Stretching Space
If there is content that depends on the space stretched by the measurement during the TextBox input process, then the stretched space may be incorrect, such as the following code:
With this logic, you will see the text content being clipped during the input process. Basically, you can see the text content being clipped under the Skia.WPF and Skia.GTK projects.
For now, the only workaround is to modify the interface design.
TextBox’s Minimum Height
The minimum height will still be higher than expected, so you can only modify the interface design to work around it.
TextBox’s Scroll Bar
For example, to scroll to the bottom, you can use the following code:
This VisualDescendant method is an auxiliary method, the code is as follows:
This method is also useful for ListView and others. The core is to find the ScrollViewer object through the visual tree and control the scrolling through the ScrollViewer.
StreamGeometry Resources for Geometric Shapes
In WPF, icons often use Path geometric paths as vector icons, which are put into StreamGeometry resources. StreamGeometry resources made from a single Path can be replaced in UNO with x:String
, as the following code shows an icon originally placed in WPF resources:
In WPF, suppose it is set on a button as an icon button, you can define a style, the content is roughly as follows:
The code used in the specific business is roughly as follows:
After moving to UNO, change the StreamGeometry type resource to an x:String
resource, as in the following code:
The rest of the code is basically the same as WPF, as in the following UNO button style
Then you can see the button code define is same as the WPF code:
PathGeometry
Some parts are not supported, so multi-platform testing is required. You may need to find a workaround.
x
Static binding is not supported, so a workaround is necessary. For example, you can redefine an instance property that references the static value, and then bind to the instance property.
Alternatively, you can move some static properties to the resource dictionary.
For instance, in WPF, you would write it like this:
In UNO, you would modify it to use the resource dictionary:
Image Resources
Image resources can use relative or absolute paths. The format for absolute paths in UNO is as follows:
The [MyApp]
in the above code is optional, but I recommend including it. This [MyApp]
corresponds to the assembly name.
By default, all images are referenced as Content
. You can see the following code in the csproj project file:
Newly added image files do not require any modifications by default. However, for platform compatibility, I recommend using png, jpg, and bmp formats, as all platforms support these formats. If your image does not display, please follow these steps:
- Check if you have modified the csproj and inadvertently ignored your image.
- Try using an absolute path for the resource.
- Compare the absolute path character by character to ensure it is correct.
- Verify that the path starts with the string
ms-appx:///
. You need to use three/
characters. - If you still can’t see the image, try regenerating it.
- If it still doesn’t work, check if the image format is unusual, such as changing the webp image extension to png, etc.
Images can be used as content in the resource dictionary. You can use the BitmapImage type, which is the same as in WPF. However, the content of the Source needs to be changed under the absolute path, as shown in the following example:
For more information, please refer to the official documentation Assets and image display
ContentControl
The functionality aligns with WPF, but the default style behavior is different. The default HorizontalContentAlignment and VerticalContentAlignment are in the top left corner. You need to set them to Stretch to align with WPF.
Default Control Properties
Most control default properties are the same as in WPF. However, a few layout properties are different. For example, many controls’ HorizontalAlignment and VerticalAlignment are in the top left corner. You need to set them to Stretch to align with WPF.
Changes to csproj
Due to some conflicts between UNO and VisualStudio, creating a new file may cause UNO’s csproj to add unnecessary code. During the development process, before uploading to git, check whether the changes to csproj are necessary. If the changes are unnecessary, please revert them. Generally, you need to revert the changes to csproj after creating a new file, such as creating a new type or user control.
Dispatcher
The Dispatcher in UNO is weaker than that in WPF, but some replacements can be made. The logic of obtaining the Dispatcher from the original interface elements remains unchanged.
The logic of obtaining it statically, such as the following WPF code, needs to be replaced.
The method of obtaining the static main thread dispatcher from UNO is the same as that of UWP or WinUI 3, as shown in the following code.
Unlike WPF’s Dispatcher scheduling level, UNO’s schedulable level is very limited, with only the following schedulable levels.
In most cases, the Normal priority is used.
However, when running WinUI 3, the acquisition of the CoreApplication.MainView.CoreWindow
property may throw an exception that it cannot be created repeatedly. If you try to get the CoreApplicationView object indirectly from CoreApplication.GetCurrentView()
to get the Dispatcher, it may still fail, because this method will throw a System.Runtime.InteropServices.COMException: “Element not found” exception.
A more secure way is to store the Microsoft.UI.Dispatching.DispatcherQueue in the App yourself, so that you can get the same DispatcherQueue object obtained from the main UI thread and use it on WinUI 3, WPF and GTK projects. In the WinUI 3 project, the MainWindow.Dispatcher property is still null, which is why the DispatcherQueue is used.
Missing Mechanisms
Visibility.Hidden
There is no hidden option, instead, you can set the opacity to 0. Setting Opacity="0"
has a similar effect to WPF’s Visibility.Hidden
.
MultiBinding
MultiBinding is not supported, so you have to find a workaround and write the interface with only single binding.
ControlTemplate.Triggers
This is not supported, a workaround is needed.
Use of x attribute in Resources
The use of x
in resources is not supported. This is because x must be assigned a property or field when it is generated, but resources can be created multiple times, which the generated code cannot handle. This issue was previously raised by Avalonia’s XAML creator, and now WinUI 3, UNO, and MAUI all have this problem.The simplest reproduction code is as follows:
In this case, you should use x:Key
instead of x:Name
to meet the expectation.
In addition, for the binding logic within resources, such as the following code, you can only find a workaround for this kind of code:
The error message for the above code is error CS0103: The name "_RootGrid" does not exist in the current context
.
For more information, please see Adding Name to a Resource fails on build · Issue #1427 · unoplatform/uno.
IPC
Known issue: https://github.com/dotnet-campus/dotnetCampus.Ipc/issues/139
References
【Chinese Blog】 WPF uses MAUI’s custom drawing logic
I share a video of an app which created with uno · unoplatform/uno · Discussion #4962
原文链接: http://blog.lindexi.com/post/Notes-on-Migrating-from-WPF-to-UNO-under-UOS
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。 欢迎转载、使用、重新发布,但务必保留文章署名 林德熙 (包含链接: https://blog.lindexi.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我 联系。