In-depth technical analysis based on XAML framework and cross-platform project architecture design

In-depth technical analysis based on XAML framework and cross-platform project architecture design

We took an in-depth look at the various XAML-based platforms, cross-platform strategies, and core technologies needed to design effective project architecture.

最后更新 11/8/2024 10:03 PM
Vicky&James
预计阅读 22 分钟
分类
.NET
标签
.NET C# WPF architecture design cross-platform

This article is based on Vicky & James 'speech at the BMW meetup conference at Microsoft headquarters in South Korea on October 22, 2024. This seminar gave an in-depth discussion of the various platforms based on XAML-based, cross-platform strategies, and core technologies needed for effective project architecture design.

introduced

大家好,我们中韩Microsoft MVP夫妇Vicky&James。我们从WPF开始就对包括Uno Platform在内的基于XAML的框架和项目架构设计有着深入的兴趣和经验。大家可以在我们的GitHub仓库中查看和下载各种项目的源代码:GitHub - jamesnetgroup

directory

  1. Overview of the XAML Platform and Cross-Platform
  2. Consider cross-platform. NET version selection strategies
  3. Analysis of connection strategy between View and ViewModel
  4. Necessary functions and implementation plan for framework design
  5. Core strategies for effectively using WPF technology on other platforms
  6. Bootstraper Design Methodology for Distributed Project Management
  7. Strategies to maximize the utilization of WPF technology across desktop cross-platforms

1. Overview of the XAML Platform and Cross-Platform

XAML is a markup language used to declaratively define UIs and is used on multiple platforms. XAML has a hierarchy of objects (i.e. classes) that enables developers to design and manage UIs in an object-oriented manner. Because of this structure, it is natural for developers to work directly with XAML.

When WPF first emerged, it emphasized collaboration between developers and designers, but in fact the XAML domain is often the responsibility of developers as well. This is because XAML is not just a simple design, but forms an object-based hierarchy that also plays an important role in complex custom control implementations. This developer-oriented design approach prompted XAML to become a core component not only in WPF, but in many subsequent platforms.

In particular, WPF has had a significant impact on all XAML-based platforms and has become the most important reference for these platforms.

1.1 Major XAML frameworks

      • WPF **: A powerful framework for Windows desktop application development that provides rich UI and graphics capabilities.
      • Silverlight : Platform for Internet applications running in web browsers, currently supported. It is a lightweight version of WPF and runs as a plug-in. Due to changes in web standards policies, plug-in-based web platforms disappeared, and ** VisualStateManager (VSM) was introduced in Silverlight 2 to make up for the shortcomings of Trigger.
      • Xamarin. Forms **: A mobile application development platform that supports iOS, Android and Windows. As the first XAML-based cross-platform based on Mono, it was strategically acquired by Microsoft and became the foundation of. NET Core.
      • UWP (Universal Windows Platform)**: A platform used to develop applications running on Windows 10 and above. You need to register for the Microsoft Store and have restrictions such as WinAPI usage restrictions. Support the same custom control design as WPF.
      • WinUI 3 **: Windows native UI framework, is the next-generation UI platform for the latest Windows application development. Inherits all the advantages of UWP while addressing its limitations and adopting the extensibility of WPF.
      • MAUI (. NET Multi-platform App UI)**: A cross-platform UI framework introduced since. NET 6, allowing mobile and desktop applications to be developed in a single project.
      • Uno Platform **: A framework that allows the use of UWP and WinUI APIs on a variety of platforms, supporting Web (WebAssembly), mobile and desktop. Supports almost all platforms and provides the same custom control design as WPF.
      • Avalonia UI **: An open source UI framework that allows WPF-style XAML to be used across platforms. Support the same custom control design as WPF, and support various platforms through unique technical extensions.
      • OpenSilver **: An open source platform optimized for migrating old Silverlight to OpenSilver. Runs in almost the same way as Silverlight and also provides a familiar environment for WPF developers.

2. Consider cross-platform. NET version selection strategies

In cross-platform application development, you need to be careful in choosing the. NET version to use. Because this will directly affect compatibility, functionality and target platform support.

2.1. NET version options

    • *. NET Framework **: For Windows only, mainly for existing WPF and WinForms applications.
    • *. NET Standard 2.0/2.1 **: A standard designed to provide compatibility between various. NET implementations.
    • *. NET (Core) 3.0 and above **: Supports cross-platform. NET implementations for Windows, macOS, and Linux, including the latest features and performance improvements.

2.2 Selection criteria and considerations

如果需要跨平台支持,应该选择.NET Core或最新的.NET。如果与现有.NET Framework库或包的兼容性很重要,那么则应该使用.NET Standard 2.0。如果想要最新功能和性能改进,就需要考虑.NET 5及以上版本。

In addition, cross-platform frameworks have considered compatibility since. NET 5.0, and continue to make functional improvements based on the latest version, so it is recommended that you choose the latest. NET version.

    • Strategic recommendations **:
  • 将通用库编写为.NET Standard 2.0以确保最大兼容性。
  • Create projects for each platform and reference common libraries.
  • 如果可能,使用.NET 6及以上版本以获得最新功能和性能改进。

3. Analysis of connection strategy between View and ViewModel

In the MVVM (Model-View-ViewModel) pattern, the connection between View and ViewModel is the core part. Differences in connection methods can lead to completely different ways of using MVVM. Therefore, we need to determine the DataContext allocation method based on the purpose of using MVVM.

3.1 Traditional direct DataContext allocation method

Create a ViewModel in the back of the code and directly assign it to the View's DataContext.

public MainWindow()
{
    InitializeComponent();
    DataContext = new MainViewModel();
}
    • Advantages **:
  • Achieve simple and intuitive
  • You can clearly control the timing of creating a view model
  • You can pass the required parameters to the constructor
    • Disadvantages **:
  • Strong coupling occurs between View and ViewModel
  • Difficult to simulate (Mock) ViewModel during unit testing
  • Difficulty taking advantage of dependency injection (DI)
  • DataContext allocation opportunities need to be specified directly, which may be difficult to maintain consistency

3.2 Creating ViewModel instances in XAML

Set a DataContext in XAML to instantiate a ViewModel.

<Window x:Class="MyApp.MainWindow"
        xmlns:local="clr-namespace:MyApp.ViewModels">
    <Window.DataContext>
        <local:MainViewModel />
    </Window.DataContext>
    <!-- Window content -->
</Window>
    • Advantages **:
  • XAML's intelligence-aware support reduces binding errors
  • You can preview the actual data binding in the designer
  • Clearly express the relationship between View and ViewModel
    • Disadvantages **:
  • Difficulties in dependency injection when creating ViewModel
  • Complex initialization logic or limited parameter passing
  • DataContext allocation timing is mandatory, reducing flexibility

3.3 ViewModel direct creation and dependent delivery

Create ViewModel directly in the background of the code and pass the required dependencies directly when passing them.

public MainWindow()
{
    InitializeComponent();
    var dataService = new DataService();
    var loggingService = new LoggingService();
    DataContext = new MainViewModel(dataService, loggingService);
}
    • Advantages **:
  • You can explicitly pass on the required dependencies when creating a ViewModel
  • Complex initialization logic can be implemented
  • ViewModel instances can be flexibly created based on Runtime
    • Disadvantages **:
  • View needs to understand ViewModel dependencies
  • As dependencies increase, the code background becomes complex
  • The coupling between View and ViewModel is still high
  • DataContext allocation opportunities need to be specified directly, which may be difficult to maintain consistency
  • Because DI is not used to manage projects, dependencies may be confusing

3.4 Utilize Dependency Injection (DI) Containers

Using DI containers to manage ViewModels and their dependencies reduces the coupling between View and ViewModels.

public MainWindow()
{
    InitializeComponent();
    DataContext = ServiceProvider.GetService<MainViewModel>();
}
    • Advantages **:
  • Reduce the coupling between View and ViewModel
  • Centralized management of dependencies improves maintainability
  • Convenient unit testing
  • Flexibility to change dependencies at run time
    • Disadvantages **:
  • Initial configuration of DI containers can be complex
  • Team members need to understand the DI model
  • You still need to create the view model directly in the DataContext, and consistency in allocation timing may be difficult to maintain
  • You need to decide whether to manage the view model as a singleton or an instance, and consider the life cycle of the view. Clear rules need to be established and strictly adhered to

3.5 View's automatic ViewModel creation strategy

In order to solve the above problems, we can consider creating a ViewModel through dependency injection and assigning it to a DataContext at the appointed time point of view creation. For example, when designing a ContentControl-based Veiw, automatic creation of ViewModels is an effective method.

public class UnoView : ContentControl
{
    public UnoView()
    {
        this.Loaded += (s, e) =>
        {
            var viewModelType = ViewModelLocator.GetViewModelType(this.GetType());
            DataContext = ServiceProvider.GetService(viewModelType);
        };
    }
}
    • Advantages **:
  • The consistency of DataContext allocation timing can be maintained
  • Reduce the coupling between View and ViewModel
  • ViewModel creation and automatic processing of dependency injection
  • View does not need to know which ViewModel you should use

This is almost a method with no shortcomings. By managing a single View, processing timing and processing logic can be unified. Good design can also be guaranteed in terms of structural improvement and expansion.

不过需要View和ViewModel之间的Mapping,可以使用Dictionary或Mapping Table 来实现。这样可以集中管理View和ViewModel之间的连接信息。关于连接管理的映射方法,我们将在后面的Bootstrapper设计方法论中详细讨论。

4. Necessary functions and implementation plan for framework design

在设计应用程序架构时,构建考虑可重用性和可扩展性的框架非常重要。为此,使用依赖注入(DI)容器是必不可少的。

4.1 Use of Dependent Injection (DI) Containers

DI是现代软件开发中不可或缺的模式,对依赖关系管理和降低耦合度有很大帮助。然而,在像WPF这样的桌面应用程序中,Web应用程序中常用的Microsoft.Extensions.DependencyInjection等DI容器可能并不完全适合。

4.1.1 Use and precautions for Microsoft. Extensions. DependencyInjection

Microsoft.Extensions.DependencyInjection是.NET官方提供的DI容器,可以说是.NET Foundation的标准。它被用于ASP.NET Core、EntityFrameworkCore、MAUI等各种平台和框架中的几乎所有系统中使用,并提供TransientScopedSingleton等生命周期管理功能。

However, in WPF, the life cycle of this standard DI may not exactly match the actual situation in WPF.

    • Precautions **:
  • 在WPF等桌面应用程序中,可能不需要Scoped生命周期
  • TransientSingleton的概念是为服务或Web应用程序设计的,在WPF中某些功能可能不适用
  • May bring unnecessary complexity, and simpler and lighter DI containers may be more appropriate for WPF usage scenarios

当然,即使不使用Transient这样的生命周期也可以使用DI,但准确理解这些要点是非常重要的。

4.1.2 Community Toolkit. DI for Mvvm

CommunityToolkit.Mvvm并不直接提供像Microsoft.Extensions.DependencyInjection这样的DI。这可能是因为Microsoft.Extensions.DependencyInjection和WPF的生命周期特性不完全匹配。

但是,CommunityToolkit.Mvvm通过提供Ioc.Default允许开发者使用任何想要的DI容器。任何实现了System.IServiceProvider接口的DI容器都可以注册使用。

因此,使用CommunityToolkit.Mvvm时可以选择DI。最常用的DI之一无疑是Microsoft.Extensions.DependencyInjection,使用Prism这样的DI也是非常有效的组合。

4.1.3 Advantages of directly designing DI containers

基于IServiceProvider接口设计DI的方法可以注册到CommunityToolkit.MvvmIoc.Default中,实现内部功能的连接和兼容。由于IServiceProvider只要求实现GetService等最基本的功能,因此可以实现非常简单的DI。

    • Advantages **:
  • Reduce project complexity by implementing a simple DI container that contains only necessary functions
  • Various functions can be designed, controlled and expanded internally
  • The overall framework architecture and project design can be accurately constructed
  • Provide a unified DI container that is independent of specific platforms, facilitating cross-platform development
    • Example code **:
// 基于IServiceProvider的DI容器实现
public class SimpleServiceProvider : IServiceProvider
{
    private readonly Dictionary<Type, Func<object>> _services = new();

    public void AddService<TService>(Func<TService> implementationFactory)
    {
        _services[typeof(TService)] = () => implementationFactory();
    }

    public object GetService(Type serviceType)
    {
        return _services.TryGetValue(serviceType, out var factory) ? factory() : null;
    }
}

// DI容器注册和使用
var serviceProvider = new SimpleServiceProvider();
serviceProvider.AddService<IMainViewModel>(() => new MainViewModel());

Ioc.Default.ConfigureServices(serviceProvider);

这样基于IServiceProvider接口实现简单的DI容器,就可以注册到CommunityToolkit.MvvmIoc.Default中,实现内部功能的连接和兼容。如果觉得使用Microsoft.Extensions.DependencyInjectionPrism等主流DI太繁重,自己直接来实现一个是非常有吸引力的选择。

    • Note **: 如果不遵循IServiceProviderSystem.ComponentModel标准,可能会失去和CommunityToolkit.MvvmIoc兼容性。但是我们可以将CommunityToolkit.Mvvm仅作为MVVM相关的模块,创建一个更专业、更统一的、不依赖特定平台或框架的DI容器。这对于创建可以在跨平台等多个XAML平台上通用的框架是非常适合的。

5. Effective use strategies of WPF technology on other platforms

To maximize the power of WPF on other XAML platforms, we need to understand some historical background and core strategies. At the same time, you also need to understand in detail the platform features that can directly use WPF technology.

5.1 Understanding of characteristics and differences between platforms

      • Differences between UWP and WinUI 3 **: As a dedicated platform for Windows 10, UWP has poor compatibility with traditional platforms such as WPF and WinForms due to application store registration guidelines and WinAPI restrictions. Therefore, WinUI 3 came into being. It not only inherits all the advantages of UWP, but also improves its existing problems and develops into a platform with high degrees of freedom like WPF.
  • Uno Platform桌面版与WinUI 3的一致性: Uno Platform支持Windows、macOS、Linux的桌面平台完全遵循WinUI 3的方式。因此,WinUI 3直接使用UWP的核心库,而Uno Platform也同样采用WinUI 3的方式,这意味着所有以Microsoft.*开头的DLL库都可以共享使用。

理解这些平台间的特征可以让我们认识到Uno Platform Desktop是一个非常高效且具有吸引力的平台。因此,在WPF和Uno Platform之间进行技术共享和转换的策略非常有效且高效,因为它们与WinUI 3和UWP都有着紧密的联系。

5.2 Make the most of VisualStateManager (VSM)

由于不是所有平台都可以直接使用WPF的Trigger,所以我们就需要一个替代策略。VisualStateManager(VSM)在解决这个问题上起着核心作用。

VSM was introduced in Silverlight 2.0 to make up for the shortcomings of Trigger and optimizes state processing between custom controls and XAML. Subsequently, in. NET 4.0, VSM was also introduced into WPF, and the internal design of all CustomControls in WPF, such as Button, CheckBox, DataGrid, and Window, was changed from Trigger to VSM.

    • Advantages **:
  • The same functionality can be achieved through VSM on platforms where Trigger cannot be used directly
  • UI state management and animation can be effectively implemented
  • VSM can be used to unify different behaviors on different platforms

Finally, by using VSM centrally, you can build the same XAML and CustomControl on WPF, Uno Platform Desktop, WinUI 3, UWP and other platforms, and the source code can be fully shared.

5.3 Flexible use of IValueConverter

IValueConverter是一个允许在数据绑定时转换值的接口,对于抽象化平台间差异非常有用。

    • Strategic use **:
  • You can implement and replace almost the same functions as Trigger and write simple and effective source code
  • Since you need to create a Converter every time and the reusability standards are vague, it is recommended not to pursue reuse too much, but to use it flexibly
  • Use it intuitively even if it is not reusable. The important thing is to minimize branches by clear naming and specialize in use
    • Limitations and supplements **:
  • 仅使用IValueConverter是有限的
  • IValueConverter应用于简单转换,复杂场景的管理会带来负担,这时我们应通过VSM解决
  • 复杂的状态处理最好使用VisualStateManager

总之,IValueConverter补充了VSM的不足,对于简单直接的转换工作应该直观灵活使用,不要过分追求重用性。

6. Bootstraper Design Methodology for Distributed Project Management

随着应用程序变得复杂和模块化,初始化过程和依赖管理变得越来越重要。Bootstrapper模式在集中管理这些初始化逻辑方面非常有用。

虽然所有平台都以Application设计为基础,但由于各平台的特性和方式不同,Application设计各不相同。因此,为了在所有平台上保持相同的开发方式,使用Bootstrapper结构设计是非常有效的。

6.1 The role and necessity of Bootstrapper

    • Bootstrapper functions **:
      • Dependency injection settings **: Initialize the DI container and register the necessary services, Views, and ViewModels.
      • Manage the connection between views and view models **: Register views through dependency injection and manage the mapping between views and view models.
      • Centralized configuration management **: All configurations are managed in Bootstrapper, so that application projects only perform their roles, and other functions are managed through project distribution and modularization.
  • In addition, you can flexibly expand centralized management projects without affecting the Application.
    • Advantages **:
  • Improve code readability and maintainability by separating the application's initialization logic.
  • Through project distribution and modularity, functional implementation can be developed independently.
  • Minimize structural differences between platforms and maintain a consistent architecture.

6.2 Bootstrapper design plan

    • Example code **:
namespace Jamesnet.Core;

public abstract class AppBootstrapper
{
    protected readonly IContainer Container;
    protected readonly ILayerManager Layer;
    protected readonly IViewModelMapper ViewModelMapper;

    protected AppBootstrapper()
    {
        Container = new Container();
        Layer = new LayerManager();
        ViewModelMapper = new ViewModelMapper();
        ContainerProvider.SetContainer(Container);
        ConfigureContainer();
    }

    protected virtual void ConfigureContainer()
    {
        Container.RegisterInstance<IContainer>(Container);
        Container.RegisterInstance<ILayerManager>(Layer);
        Container.RegisterInstance<IViewModelMapper>(ViewModelMapper);
        Container.RegisterSingleton<IViewModelInitializer, DefaultViewModelInitializer>();
    }

    protected abstract void RegisterViewModels();
    protected abstract void RegisterDependencies();

    public void Run()
    {
        RegisterViewModels();
        RegisterDependencies();
        OnStartup();
    }

    protected abstract void OnStartup();
}

Through such abstraction, the management structure can be clearly emphasized and the timing and order can be controlled through virtual methods. This helps flexibly extend and refine without affecting the Application, allowing it to run in a consistent manner across various platforms.

7. Strategies for maximizing WPF technology in cross-platform desktop environments

Development efficiency can be improved by making the most of the technologies and patterns used in WPF in other XAML-based cross-platform frameworks.

7.1 Implement a framework that runs on all platforms

Jamesnet.Core是基于.NET Standard 2.0的框架,允许在WPF、Uno Platform和WinUI 3中实现相同的项目设计。该框架具有以下特点:

  • DI design: Using the DI container based on IServiceProvider, it can be used with CommunityToolkit. Mvvm.
  • MVVM Bootstrapper: Centrally manage project initialization and dependency injection.
  • Connection management between View and ViewModel: Reduce the coupling between View and ViewModel through layer management and other methods.
  • Run uniformly on all XAML-based platforms.
  • Directly reference the repository source code for easy debugging, function implementation, extension and research.
    • Advantages **:
  • Whether you develop using WPF, Uno Platform, or WinUI 3, you can maintain the same architecture.
  • 使用Uno Platform Desktop可以在macOS和Linux上进行开发和运行。
  • 可以使用JetBrains Rider构建跨平台开发环境。

7.2 Practical implementation case analysis

    • League of Legends client refactoring project ** utilizes the Jamesnet.Core framework to implement it using the same code base and architecture on different platforms such as WPF, Uno Platform and WinUI3.

    • Strategic approach **:
  • Maintain the unity of ** project design through the ** Jamesnet.Core framework **.
  • Centrally manage views and view models with ** DI containers and Bootstrapper **.
  • 使用VisualStateManager(VSM)替代Trigger,在不同平台上以相同方式管理UI状态。
    • Outcome **:
  • ** More than 97% of code is shared **, maximizing the possibility of expansion to other platforms.
  • Providing consistent user experience and development methodology on a variety of platforms makes technology transition easier.
  • Through project decentralization, modularization and centralized management, development and maintenance costs have been greatly reduced.
  • Through the modular development of **CustomControl **, refactoring and scalability have been improved, and the decentralized view system is also more effective in **AI applications such as GPT and Claude.

conclusion

WPF technology and patterns are still powerful, and applying them to cross-platform development can improve development efficiency and code reuse. In particular, using the **Jamesnet.Core framework **, through the centralized management strategy of DI containers and the introduction of Bootstraper, helps reduce the coupling between views and view models and improve maintainability.

In addition, by actively using VisualStateManager and IValueConverter, differences between platforms can be minimized and consistent designs maintained. Through these strategies, we can transcend the foundation of WPF and strategically achieve cross-platform technology expansion.

In particular, XAML-related DLLs are used 100% equally between UWP, WinUI 3, and Uno Platform, so there are few differences between these platforms. Therefore, for WPF developers, ** using the Uno Platform desktop edition is very effective and strategic **. This is because the conversion from WPF to Uno can be completed in a matter of hours, and the conversion to WinUI 3 is also very easy.

In the future, WPF technology and XAML-based frameworks will continue to develop, and using these for cross-platform development will become even more important. Developers need to grasp these trends well, formulate appropriate strategies, and develop high-quality applications.

reference

main warehouse

Currently updated WPF tutorial (Custom Controls)

Keep Exploring

延伸阅读

更多文章
同分类 / 同标签 5/27/2025

WPF achieves a danger warning effect

When the program we write is released, the user is doing some dangerous operations. Our software should give some reminder effects, such as red on the edge of the border, similar to the alarm reminder effect like Gaode Map

继续阅读
同分类 / 同标签 6/20/2024

CodeWF.EventBus: Lightweight event bus for smoother communication

CodeWF.EventBus, a flexible event bus library that enables decoupling communication between modules. Supports multiple. NET project types, such as WPF, WinForms, ASP.NET Core, etc. Adopt concise design to easily implement command publishing and subscribing, request and response. Ensure that incidents are properly handled through orderly incident handling. Streamline your code and improve system maintainability.

继续阅读