This article is based on the presentation given by Vicky & James at the Microsoft Korea Headquarters BMW Meetup on October 22, 2024. In this workshop, we delved into various XAML-based platforms, cross-platform strategies, and the core technologies needed for effective project architecture design.
Introduction
Hello everyone, we are the Korea-China Microsoft MVP couple Vicky & James. Since WPF, we have had deep interest and experience in XAML-based frameworks and project architecture design, including the Uno Platform. You can view and download the source code for various projects in our GitHub repository: GitHub - jamesnetgroup

Table of Contents
- Overview of XAML Platforms and Cross-Platform
- .NET Version Selection Strategy Considering Cross-Platform
- Analysis of View and ViewModel Connection Strategies
- Essential Features and Implementation for Framework Design
- Core Strategies for Effectively Using WPF Technologies on Other Platforms
- Bootstrapper Design Methodology for Distributed Project Management
- Strategies for Maximizing WPF Technologies in Desktop Cross-Platform
1. Overview of XAML Platforms and Cross-Platform
XAML is a markup language used to declaratively define UI and is used on multiple platforms. XAML has a hierarchy composed of objects (i.e., classes), allowing developers to design and manage UI in an object-oriented manner. Due to this structure, it is natural for developers to handle XAML directly.
When WPF first emerged, it emphasized collaboration between developers and designers, but in practice, the XAML area is often handled by developers. This is because XAML is not just about simple design; it forms an object-based hierarchy and plays an important role in complex custom control implementation. This developer-oriented design approach led to XAML becoming a core component not only in WPF but also in many platforms that followed.
In particular, WPF has had a significant influence 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, providing rich UI and graphics capabilities.
- Silverlight: A platform for internet applications running in web browsers, now discontinued. It was a lightweight version of WPF that ran as a plugin. Due to changes in web standard policies, plugin-based web platforms disappeared. In Silverlight 2, VisualStateManager (VSM) was introduced to compensate for the shortcomings of Triggers.
- Xamarin.Forms: A mobile application development platform supporting iOS, Android, and Windows. As the first XAML-based cross-platform built on Mono, it was strategically acquired by Microsoft and became the foundation for .NET Core.
- UWP (Universal Windows Platform): A platform for developing applications that run on Windows 10 and later. It requires Microsoft Store registration and has constraints such as WinAPI usage restrictions. It supports custom control design similar to WPF.
- WinUI 3: A native Windows UI framework and the next-generation UI platform for the latest Windows app development. It inherits all the advantages of UWP while addressing its limitations and adopts the extensibility of WPF.
- MAUI (.NET Multi-platform App UI): A cross-platform UI framework introduced from .NET 6, enabling development of mobile and desktop applications in a single project.
- Uno Platform: A framework that allows using UWP and WinUI APIs on various platforms, supporting Web (WebAssembly), mobile, and desktop. It supports almost all platforms and provides custom control design identical to WPF.
- Avalonia UI: An open-source UI framework that allows using WPF-style XAML on cross-platforms. It supports custom control design similar to WPF and extends support to various platforms through unique technologies.
- OpenSilver: An open-source platform optimized for migrating old Silverlight applications to OpenSilver. It operates in almost the same way as Silverlight and also provides a familiar environment for WPF developers.
2. .NET Version Selection Strategy Considering Cross-Platform
In cross-platform application development, careful selection of the .NET version to use is necessary. This directly affects compatibility, functionality, and target platform support.
2.1 .NET Version Options
- .NET Framework: Windows only, primarily used for existing WPF and WinForms applications.
- .NET Standard 2.0 / 2.1: A standard designed to provide compatibility among various .NET implementations.
- .NET (Core) 3.0 and later: A cross-platform .NET implementation supporting Windows, macOS, and Linux, including the latest features and performance improvements.
2.2 Selection Criteria and Considerations
If cross-platform support is needed, choose .NET Core or the latest .NET. If compatibility with existing .NET Framework libraries or packages is important, use .NET Standard 2.0. If you want the latest features and performance improvements, consider .NET 5 and later.
Additionally, cross-platform frameworks have considered compatibility since .NET 5.0 and continue to improve features based on the latest version, so it is recommended to choose the latest .NET version.
Strategic Recommendations:
- Write common libraries as
.NET Standard 2.0to ensure maximum compatibility. - Create projects for each platform and reference the common library.
- If possible, use
.NET 6 and laterfor the latest features and performance improvements.
3. Analysis of View and ViewModel Connection Strategies
In the MVVM (Model-View-ViewModel) pattern, the connection between View and ViewModel is a core part. The connection method greatly affects how MVVM is used. Therefore, we need to decide the DataContext assignment method based on the purpose of using MVVM.
3.1 Traditional Direct DataContext Assignment
Create a ViewModel in the code-behind and assign it directly to the View's DataContext.
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
Advantages:
- Simple and intuitive implementation
- Clear control over the creation timing of the ViewModel
- Ability to pass required parameters to the constructor
Disadvantages:
- Strong coupling between View and ViewModel
- Difficult to mock ViewModel for unit testing
- Hard to leverage dependency injection (DI)
- Need to directly specify the timing of DataContext assignment, which may make consistency hard to maintain
3.2 Creating ViewModel Instances in XAML
Set the DataContext in XAML to instantiate the ViewModel.
<Window x:Class="MyApp.MainWindow"
xmlns:local="clr-namespace:MyApp.ViewModels">
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<!-- Window content -->
</Window>
Advantages:
- IntelliSense support in XAML reduces binding errors
- Preview actual data bindings in the designer
- Clearly expresses the relationship between View and ViewModel
Disadvantages:
- Difficult to perform dependency injection when creating the ViewModel
- Complex initialization logic or parameter passing is limited
- DataContext assignment timing is forced, reducing flexibility
3.3 Direct ViewModel Creation with Dependency Passing
Create the ViewModel in code-behind and pass required dependencies directly.
public MainWindow()
{
InitializeComponent();
var dataService = new DataService();
var loggingService = new LoggingService();
DataContext = new MainViewModel(dataService, loggingService);
}
Advantages:
- Clear passing of required dependencies when creating ViewModel
- Can implement complex initialization logic
- Flexible creation of ViewModel instances based on runtime conditions
Disadvantages:
- View needs to know about ViewModel's dependencies
- Code-behind becomes complex as dependencies increase
- Still high coupling between View and ViewModel
- Need to directly specify DataContext assignment timing, making consistency hard to maintain
- Without DI management, dependency relationships can become chaotic
3.4 Leveraging Dependency Injection (DI) Containers
Using a DI container to manage ViewModels and their dependencies reduces coupling between View and ViewModel.
public MainWindow()
{
InitializeComponent();
DataContext = ServiceProvider.GetService<MainViewModel>();
}
Advantages:
- Reduced coupling between View and ViewModel
- Centralized dependency management improves maintainability
- Facilitates unit testing
- Flexible runtime changes to dependencies
Disadvantages:
- Initial configuration of the DI container can be complex
- Team members need to understand the DI pattern
- Still need to create ViewModel directly in DataContext, making consistency hard to maintain
- Need to decide whether to manage ViewModels as singletons or instances and consider the View's lifecycle. Clear rules must be established and strictly followed.
3.5 Automatic ViewModel Creation Strategy for Views
To address the above issues, we can consider automatically creating ViewModel and assigning it to DataContext at a convention-based timing when the View is created. For example, designing a View based on ContentControl that automatically creates a ViewModel is an effective approach.
public class UnoView : ContentControl
{
public UnoView()
{
this.Loaded += (s, e) =>
{
var viewModelType = ViewModelLocator.GetViewModelType(this.GetType());
DataContext = ServiceProvider.GetService(viewModelType);
};
}
}
Advantages:
- Consistent timing of DataContext assignment
- Reduced coupling between View and ViewModel
- Automatic handling of ViewModel creation and dependency injection
- View does not need to know which ViewModel to use
This method has almost no drawbacks. By managing a single View, timing and handling logic can be unified. It also ensures good design in terms of structural completeness and extensibility.
However, mapping between View and ViewModel is required, which can be implemented using a Dictionary or Mapping Table. This allows centralized management of connection information between Views and ViewModels. We will discuss the mapping method for connection management in detail later in the Bootstrapper Design Methodology.
4. Essential Features and Implementation for Framework Design
When designing an application architecture, it is important to build a framework that considers reusability and extensibility. To do this, using a dependency injection (DI) container is essential.
4.1 Use of Dependency Injection (DI) Containers
DI is an indispensable pattern in modern software development, greatly aiding dependency management and reducing coupling. However, in desktop applications like WPF, DI containers commonly used in web applications, such as Microsoft.Extensions.DependencyInjection, may not be entirely suitable.
4.1.1 Usage and Considerations of Microsoft.Extensions.DependencyInjection
Microsoft.Extensions.DependencyInjection is the official DI container provided by .NET and can be considered the standard of .NET Foundation. It is used in various platforms and frameworks such as ASP.NET Core, EntityFrameworkCore, and MAUI, providing lifecycle management like Transient, Scoped, and Singleton.
However, in WPF, the lifecycle of this standard DI may not perfectly match the actual requirements of WPF.
Considerations:
- In desktop applications like WPF, the
Scopedlifecycle may not be needed. - Concepts like
TransientorSingletonare designed for service or web applications and may not be fully applicable in WPF. - It may introduce unnecessary complexity. For WPF usage scenarios, a simpler and lighter DI container may be more appropriate.
Of course, even without using lifecycles like Transient, DI can still be used, but it is important to accurately understand these points.
4.1.2 DI in CommunityToolkit.Mvvm
CommunityToolkit.Mvvm does not directly provide a DI container like Microsoft.Extensions.DependencyInjection. This may be because Microsoft.Extensions.DependencyInjection and WPF's lifecycle characteristics do not perfectly match.
However, CommunityToolkit.Mvvm provides Ioc.Default, allowing developers to use any DI container they want. Any DI container that implements the System.IServiceProvider interface can be registered and used.
Therefore, when using CommunityToolkit.Mvvm, you have the freedom to choose a DI container. One of the most commonly used DI containers is undoubtedly Microsoft.Extensions.DependencyInjection, and using a DI like Prism is also a very effective combination.
4.1.3 Advantages of Directly Designing a DI Container
A DI container designed based on the IServiceProvider interface can be registered with CommunityToolkit.Mvvm's Ioc.Default, achieving internal feature connectivity and compatibility. Since IServiceProvider only requires implementing basic functions like GetService, it is possible to implement a very simple DI container.
Advantages:
- Implement a simple DI container with only necessary features, reducing project complexity.
- Design, control, and extend various functionalities internally.
- Accurately build the overall framework architecture and project design.
- Provide a unified DI container independent of specific platforms, beneficial for cross-platform development.
Example Code:
// DI container implementation based on IServiceProvider
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 container registration and usage
var serviceProvider = new SimpleServiceProvider();
serviceProvider.AddService<IMainViewModel>(() => new MainViewModel());
Ioc.Default.ConfigureServices(serviceProvider);
By implementing a simple DI container based on the IServiceProvider interface, it can be registered with CommunityToolkit.Mvvm's Ioc.Default, achieving internal feature connectivity and compatibility. If using mainstream DI containers like Microsoft.Extensions.DependencyInjection or Prism feels too heavy, implementing your own is a very attractive option.
Note:
If you do not follow the System.ComponentModel standard like IServiceProvider, you may lose compatibility with CommunityToolkit.Mvvm's Ioc. However, you can use CommunityToolkit.Mvvm only as an MVVM-related module and create a more specialized, unified DI container that does not depend on a specific platform or framework. This is suitable for creating a framework that can be used across multiple XAML platforms, such as cross-platform.
5. Core Strategies for Effectively Using WPF Technologies on Other Platforms
To maximize WPF's powerful features on other XAML platforms, we need to understand some historical context and core strategies. We also need detailed knowledge of the platform characteristics that allow direct use of WPF technologies.
5.1 Understanding Platform Characteristics and Differences
Differences between UWP and WinUI 3: UWP, as a platform dedicated to Windows 10, had poor compatibility with traditional platforms like WPF and WinForms due to App Store registration guidelines and WinAPI restrictions. Therefore, WinUI 3 was created, inheriting all of UWP's advantages while addressing its issues, evolving into a platform with high freedom like WPF.
Uno Platform Desktop Consistency with WinUI 3: Uno Platform supports desktop platforms Windows, macOS, and Linux fully following the WinUI 3 approach. Therefore, WinUI 3 directly uses UWP's core libraries, and Uno Platform also adopts the WinUI 3 approach, meaning all DLLs starting with
Microsoft.*can be shared.
Understanding these platform characteristics reveals that Uno Platform Desktop is a very efficient and attractive platform. Therefore, strategies for sharing and converting technologies between WPF and Uno Platform are very effective and efficient, as they are closely related to WinUI 3 and UWP.
5.2 Fully Leveraging VisualStateManager (VSM)
Since not all platforms can directly use WPF's Trigger, an alternative strategy is needed. VisualStateManager (VSM) plays a central role in solving this problem.
VSM was introduced in Silverlight 2.0 to compensate for the lack of Triggers and is optimized for state handling in custom controls and XAML. Subsequently, VSM was also introduced in WPF in .NET 4.0, and the internal design of all CustomControls in WPF, such as Button, CheckBox, DataGrid, and Window, was changed from Trigger to VSM.
Advantages:
- On platforms where Trigger cannot be used directly, VSM can achieve the same functionality.
- Effectively implement UI state management and animations.
- Unify different behaviors across platforms through VSM.
Ultimately, by focusing on using VSM, it is possible to build the same XAML and CustomControls on platforms such as WPF, Uno Platform Desktop, WinUI 3, and UWP, with fully shared source code.
5.3 Flexible Use of IValueConverter
IValueConverter is an interface that allows value conversion during data binding and is useful for abstracting platform differences.
Strategic Use:
- Can implement and replace almost the same functionality as Trigger, writing simple and effective source code.
- Since converters need to be created each time and reusability standards are vague, it is recommended to use them flexibly without overemphasizing reusability.
- Even without reusability, use them intuitively; the important thing is to minimize branching through clear naming and specialize usage.
Limitations and Supplements:
- Using only
IValueConverterhas limitations. IValueConverteris suitable for simple conversions; managing complex scenarios can be burdensome. For such cases, we should useVSM.- Complex state processing is best handled with
VisualStateManager.
In summary, IValueConverter complements VSM's shortcomings and should be used intuitively and flexibly for simple and direct conversions, without overemphasizing reusability.
6. Bootstrapper Design Methodology for Distributed Project Management
As applications become complex and modular, initialization processes and dependency management become increasingly important. The Bootstrapper pattern is very useful for centrally managing such initialization logic.
Although all platforms are based on Application design, the characteristics and methods of each platform differ, so Application designs vary. Therefore, using a Bootstrapper structure design is very effective for maintaining the same development approach across all platforms.
6.1 Role and Necessity of Bootstrapper
Functions of Bootstrapper:
- Dependency Injection Setup: Initialize the DI container, register necessary services, Views, and ViewModels.
- Manage View and ViewModel Connections: Register Views through dependency injection and manage the mapping between Views and ViewModels.
- Centralized Configuration Management: All configurations are managed in the Bootstrapper, allowing the application project to only perform its role, with the rest of the functionality implemented through distributed and modular projects.
- Additionally, the centralized management project can be flexibly extended without affecting the Application.
Advantages:
- Improve code readability and maintainability by separating the application's initialization logic.
- Through project distribution and modularization, functionality can be developed independently.
- Minimize structural differences between platforms, maintaining a consistent architecture.
6.2 Bootstrapper Design Approach
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 timing and order can be controlled via virtual methods. This helps with flexible expansion and improvement without affecting the Application, enabling consistent operation on various platforms.
7. Strategies for Maximizing WPF Technologies in Cross-Platform Desktop Environments
By maximizing the use of technologies and patterns from WPF in other XAML-based cross-platform frameworks, development efficiency can be improved.
7.1 Implementing a Framework That Runs on All Platforms

Jamesnet.Core is a framework based on .NET Standard 2.0 that allows the same project design to be implemented in WPF, Uno Platform, and WinUI 3. This framework has the following characteristics:
- DI Design: Utilizes an IServiceProvider-based DI container that can work with CommunityToolkit.Mvvm.
- MVVM Bootstrapper: Centrally manages project initialization and dependency injection.
- View and ViewModel Connection Management: Reduces coupling between View and ViewModel through layer management.
- Operates uniformly on all XAML-based platforms.
- Directly references repository source code, facilitating debugging, feature implementation, extension, and research.
Advantages:
- Maintain the same architecture whether developing in WPF, Uno Platform, or WinUI 3.
- Use
Uno Platform Desktopto develop and run on macOS and Linux. - Build a cross-platform development environment using
JetBrains Rider.
7.2 Case Study of Actual Implementation
The League of Legends Client Reconstruction Project uses the Jamesnet.Core framework to implement the same codebase and architecture on different platforms such as WPF, Uno Platform, and WinUI 3.




- WPF Version: GitHub - leagueoflegends-wpf
- Uno Platform Version: GitHub - leagueoflegends-uno
- WinUI 3 Version: GitHub - leagueoflegends-winui3
Strategic Approach:
- Maintain uniformity of project design through the Jamesnet.Core framework.
- Centrally manage Views and ViewModels using DI container and Bootstrapper.
- Use
VisualStateManager (VSM)to replace Trigger, managing UI state in the same way across different platforms.
Results:
- Over 97% code sharing, maximizing the possibility of extending to other platforms.
- Consistent user experience and development methodology on various platforms, making technology transitions easier.
- Through project decentralization, modularization, and centralized management, development and maintenance costs are greatly reduced.
- Modular development of CustomControls improves refactoring and extensibility. In AI applications like GPT and Claude, a decentralized view system is also more effective.
Conclusion
WPF technologies and patterns remain powerful, and applying them to cross-platform development can improve development efficiency and code reusability. In particular, using the Jamesnet.Core framework, with its centralized management strategy via a DI container and the introduction of a Bootstrapper, helps reduce coupling between Views and ViewModels and improves maintainability.
Additionally, actively using VisualStateManager and IValueConverter minimizes platform differences and maintains consistent design. Through these strategies, WPF can serve as a foundation for strategically expanding cross-platform technologies.
Notably, UWP, WinUI 3, and Uno Platform use XAML-related DLLs 100% identically, so there is almost no difference between these platforms. Therefore, for WPF developers, using Uno Platform Desktop is very effective and strategic. This is because migrating from WPF to Uno can be done in hours, and transitioning to WinUI 3 is also very easy.
In the future, WPF technologies and XAML-based frameworks will continue to evolve, and cross-platform development using them will become more important. Developers need to grasp these trends well, formulate appropriate strategies, and develop high-quality applications.
References
Main Repositories
- Jamesnet.Core Framework: GitHub - jamesnet.core
- A framework that runs on all XAML-based platforms, providing DI, MVVM, Bootstrapper, etc.
- League of Legends Client Reconstruction Project:
- WPF Version: GitHub - leagueoflegends-wpf
- Uno Platform Version: GitHub - leagueoflegends-uno
- WinUI 3 Version: GitHub - leagueoflegends-winui3
WPF Tutorials (Custom Controls) Updated So Far
- Implementing Theme Switching
- Implementing Riot PlayButton
- Implementing Navigation Bar
- Implementing Riot Slider
- Implementing Smart Date
- Implementing Cupertino TreeView
