この記事は、2024年10月22日に韓国マイクロソフト本社で開催されたBMW MeetupカンファレンスでのVicky&Jamesのプレゼンテーションを基にしています。このワークショップでは、XAMLベースのさまざまなプラットフォーム、クロスプラットフォーム戦略、効果的なプロジェクトアーキテクチャ設計に必要なコアテクノロジーについて詳しく説明しました。
プレゼンテーション:プレゼンテーション
大家好,我们中韩Microsoft MVP夫妇Vicky&James。我们从WPF开始就对包括Uno Platform在内的基于XAML的框架和项目架构设计有着深入的兴趣和经验。大家可以在我们的GitHub仓库中查看和下载各种项目的源代码:GitHub - jamesnetgroup

目次目次
- XAMLプラットフォームおよびクロスプラットフォームの概要
- クロスプラットフォームの. NETバージョン選択戦略を検討する
- ViewとViewModelの接続ポリシー分析
- フレームワーク設計に必要な機能と実現案
- 他のプラットフォームでWPF技術を効果的に使用するためのコア戦略
- 分散プロジェクト管理のためのBootstrapper設計方法論
- デスクトップクロスプラットフォームでWPFテクノロジーを最大限に活用するための戦略
1. XAMLプラットフォームおよびクロスプラットフォームの概要
XAMLは、UIを宣言的に定義するためのマークアップ言語であり、複数のプラットフォームで使用されている。XAMLは、開発者がオブジェクト指向の方法でUIを設計および管理することを可能にする、オブジェクトすなわちクラスの階層構造を持っています。この構造のため、開発者はXAMLを直接扱うのが自然です。
WPFが最初に登場したとき、それは開発者と設計者の間のコラボレーションを強調したが、実際にはXAML領域も通常開発者の責任である。これは、XAMLが単純な設計ではなく、複雑なカスタムコントロール実装で重要な役割を果たすオブジェクトベースの階層を形成するためです。この開発者指向の設計アプローチにより、XAMLはWPFだけでなく、その後の多くのプラットフォームのコアコンポーネントとなった。
特に、WPFは、すべてのXAMLベースのプラットフォームに大きな影響を与え、これらのプラットフォームの最も重要な参照点となっています。
1.1 XAMLフレームワークの概要
- WPF 豊富なUIおよびグラフィックス機能を備えた、Windowsデスクトップアプリケーション開発用の強力なフレームワーク。
- Silverlight Webブラウザで動作するインターネットアプリケーション用のプラットフォームです。現在はサポート終了です。WPFの軽量バージョンであり、プラグインとして動作します。Web標準ポリシーの変更により、プラグインベースのWebプラットフォームは消滅し、Triggerの欠点を補うためにSilverlight 2にVisual State Manager VSM ** が導入された。
- Xamarin.Forms iOS、Android、Windows対応のモバイルアプリ開発プラットフォーム。Monoベースの最初のXAMLベースのクロスプラットフォームとして、マイクロソフトに戦略的に買収され、. NET Coreの基盤となった。
- **UWP Universal Windows Platform ** Windows 10以上で動作するアプリケーションを開発するためのプラットフォーム。Microsoft Storeへの登録が必要で、WinAPIの使用制限などの制約があります。WPFと同じカスタムコントロールデザインをサポートします。
- WinUI 3 WindowsネイティブUIフレームワークであり、最新のWindowsアプリケーション開発のための次世代UIプラットフォームです。UWPのすべての利点を継承しつつ、その制限に対処し、WPFの拡張性を取り入れている。
- **MAUI. NET Multi-platform App UI **. NET 6以降に導入されたクロスプラットフォームUIフレームワークで、モバイルアプリケーションとデスクトップアプリケーションを単一のプロジェクトで開発できます。
- Uno Platform Web、モバイル、およびデスクトップをサポートする、さまざまなプラットフォームでUWPおよびWinUIのAPIを使用できるフレームワーク。ほぼすべてのプラットフォームをサポートし、WPFと同じカスタムコントロール設計を提供します。
- Avalonia UI WPFスタイルのXAMLをクロスプラットフォームで使用できるオープンソースのUIフレームワーク。WPFと同じカスタムコントロール設計をサポートし、独自の技術拡張によりさまざまなプラットフォームをサポートします。
- OpenSilver 古いSilverlightをOpenSilverに移行するために最適化されたオープンソースプラットフォーム。Silverlightとほぼ同じ方法で動作し、WPF開発者に使い慣れた環境を提供する。
2. クロスプラットフォームの. NETバージョン選択戦略を検討する
クロスプラットフォームアプリケーション開発では、使用する. NETのバージョンを慎重に選択する必要があります。これは、互換性、機能性、ターゲットプラットフォームのサポートに直接影響します。
2.1. NETバージョン·オプション{{. NETばーじょんおぷしょん}}
- . NET Framework Windows専用で、主に既存のWPFおよびWinFormsアプリケーションで使用されます。
- . NET Standard 2.0 / 2.1-様々な. NET実装间の性を提供するためにされた。
- . NET Core 3.0以上 Windows、macOS、Linuxのクロスプラットフォームの. NET実装をサポートし、最新の機能とパフォーマンスの向上が含まれています。
2.2選択基準と考慮事項
如果需要跨平台支持,应该选择.NET Core或最新的.NET。如果与现有.NET Framework库或包的兼容性很重要,那么则应该使用.NET Standard 2.0。如果想要最新功能和性能改进,就需要考虑.NET 5及以上版本。
また、クロスプラットフォームフレームワークでは、. NET 5.0以降の互換性を考慮し、最新バージョンに基づいて機能向上を続けているため、最新バージョンの. NETを選択することをお勧めします。
** 戦略的提言 **
- 将通用库编写为
.NET Standard 2.0以确保最大兼容性。 - プラットフォームごとにプロジェクトを作成し、共通のライブラリを参照します。
- 如果可能,使用
.NET 6及以上版本以获得最新功能和性能改进。
3. ViewとViewModelの接続ポリシー分析
MVVM Model-View-ViewModelモードでは、ViewとViewModelとの接続がコア部分である。接続方法が異なると、MVVMの使用方法が全く異なります。したがって、MVVMを使用する目的に応じてDataContextの割り当て方法を決定する必要がある。
3.1従来のデータコンテキストの直接割り当て
ViewModelはコードのバックグラウンドで作成され、ViewのDataContextに直接割り当てられます。
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
** メリット ***
- シンプルな直感を実現
- ビューモデルの作成タイミングをに制御できる
- コンストラクタに必要なパラメータを渡すことができます
** 欠点 ***
- ViewとViewModelの間の強い結合
- ユニットテスト时にモークが难しいViewModel
- 依存注入(DI)の利用が困難
- DataContext割当てタイミングを直接指定する必要があり、一貫性を維持することが困難になる場合がある
3.2 XAMLでViewModelインスタンスを作成する
ViewModelをインスタンス化するためにXAMLでDataContextを設定します。
<Window x:Class="MyApp.MainWindow"
xmlns:local="clr-namespace:MyApp.ViewModels">
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<!-- Window content -->
</Window>
** メリット ***
- XAMLのIntelligent Awareサポートがバインディングエラーを削減
- デザイナで実际のデータバインドをプレビューできます
- ViewとViewModelの関係を明確にする
** 欠点 ***
- ViewModel作成時の依存性注入が難しい
- 複雑な初期化ロジックやパラメータ渡しの制限
- DataContext割当てタイミングが強制され、柔軟性が低下する
3.3 ViewModelの直接作成と依存性転送
ViewModelの直接作成と依存関係の渡し時に必要な依存関係を直接渡します。
public MainWindow()
{
InitializeComponent();
var dataService = new DataService();
var loggingService = new LoggingService();
DataContext = new MainViewModel(dataService, loggingService);
}
** メリット ***
- ViewModel作成時に必要な依存関係を明示的に渡すことができます。
- 複雑な初期化ロジックを実装できる
- Runtimeに基づいてViewModelインスタンスを柔軟に作成可能
** 欠点 ***
- ViewModelの依存関係を理解する必要がある
- 依存関係が増大するにつれて、コードのバックグラウンドが複雑になる
- ViewとViewModelの結合度は依然として高い。
- DataContext割当てタイミングを直接指定する必要があり、一貫性を維持することが困難になる場合がある
- DIを使用して項目を管理しないため、依存関係が乱れてしまう場合がある
3.4依存注入DIコンテナの活用
DIコンテナを使用してViewModelとその依存関係を管理すると、ViewとViewModel間の結合を減らすことができます。
public MainWindow()
{
InitializeComponent();
DataContext = ServiceProvider.GetService<MainViewModel>();
}
** メリット ***
- ViewとViewModelの結合を減らす
- 依存関係の一元管理、保守性の向上
- ユニットテストの容易化
- 実行時に依存関係を柔軟に変更できる
** 欠点 ***
- DIコンテナの初期設定は複雑になる場合があります
- チームメンバーはDIモデルを理解する必要がある
- DataContext内で直接ビューモデルを作成する必要があり、割り当てタイミングの一貫性を維持することは困難である可能性がある
- ビューモデルをシングルトンとして管理するか、インスタンスとして管理するかを決定し、ビューのライフサイクルを考慮する必要がある。明確なルールと厳格な遵守が必要
3.5ビューの自動ViewModel作成ポリシー
上記の問題を解決するために、View作成の約定時点で、Dependency InjectionによりViewModelを作成し、DataContextに割り当てることを考えることができる。たとえば、Content ControlベースのVeiwを設計する場合、ViewModelの自動作成は効果的なアプローチです。
public class UnoView : ContentControl
{
public UnoView()
{
this.Loaded += (s, e) =>
{
var viewModelType = ViewModelLocator.GetViewModelType(this.GetType());
DataContext = ServiceProvider.GetService(viewModelType);
};
}
}
** メリット ***
- DataContextの割り当てタイミングの一貫性を維持できる
- ViewとViewModelの結合を減らす
- ViewModelの作成と依存性注入の自動化
- ビューはどのビューモデルを使用するかを知る必要はありません
これはほとんど欠点のない方法であり、単一のViewを管理することで、処理タイミングと処理ロジックを統一することができる。構造的な改善と拡張の面でも優れた設計を保証します。
不过需要View和ViewModel之间的Mapping,可以使用Dictionary或Mapping Table 来实现。这样可以集中管理View和ViewModel之间的连接信息。关于连接管理的映射方法,我们将在后面的Bootstrapper设计方法论中详细讨论。
4. フレームワーク設計に必要な機能と実現案
在设计应用程序架构时,构建考虑可重用性和可扩展性的框架非常重要。为此,使用依赖注入(DI)容器是必不可少的。
4.1依存注入(DI)コンテナの使用方法
DI是现代软件开发中不可或缺的模式,对依赖关系管理和降低耦合度有很大帮助。然而,在像WPF这样的桌面应用程序中,Web应用程序中常用的Microsoft.Extensions.DependencyInjection等DI容器可能并不完全适合。
4.1.1 Microsoft. Extension.DependencyInjectionの使用と考慮事項
Microsoft.Extensions.DependencyInjection是.NET官方提供的DI容器,可以说是.NET Foundation的标准。它被用于ASP.NET Core、EntityFrameworkCore、MAUI等各种平台和框架中的几乎所有系统中使用,并提供Transient、Scoped、 Singleton等生命周期管理功能。
しかしながら、WPFでは、このような標準DIのライフサイクルは、WPFの実際の状況と完全に一致しない場合がある。
**注意事項 **
- 在WPF等桌面应用程序中,可能不需要
Scoped生命周期 Transient或Singleton的概念是为服务或Web应用程序设计的,在WPF中某些功能可能不适用- 不要な複雑さをもたらす可能性があり、WPFの使用シナリオには、より単純で軽量なDIコンテナがより適している可能性がある
当然,即使不使用Transient这样的生命周期也可以使用DI,但准确理解这些要点是非常重要的。
4.1.2 CommunityToolkit.MvvmのDI
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 DI容器を直接設計する利点
基于IServiceProvider接口设计DI的方法可以注册到CommunityToolkit.Mvvm的Ioc.Default中,实现内部功能的连接和兼容。由于IServiceProvider只要求实现GetService等最基本的功能,因此可以实现非常简单的DI。
** メリット ***
- 必要な機能のみを含むシンプルなDIコンテナを実装し、プロジェクトの複雑さを軽減
- さまざまな機能を社内で設計、制御、拡張できる
- 全体的なフレームワークアーキテクチャとプロジェクト設計を正確に構築できます
- 特定のプラットフォームに依存しない統合DIコンテナを提供し、クロスプラットフォーム開発を促進
** サンプルコード **
// 基于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.Mvvm的Ioc.Default中,实现内部功能的连接和兼容。如果觉得使用Microsoft.Extensions.DependencyInjection、Prism等主流DI太繁重,自己直接来实现一个是非常有吸引力的选择。
*** ご注意ください。
如果不遵循IServiceProvider等System.ComponentModel标准,可能会失去和CommunityToolkit.Mvvm的Ioc兼容性。但是我们可以将CommunityToolkit.Mvvm仅作为MVVM相关的模块,创建一个更专业、更统一的、不依赖特定平台或框架的DI容器。这对于创建可以在跨平台等多个XAML平台上通用的框架是非常适合的。
5. 他のプラットフォームでのWPF技術の効果的な使用戦略
他のXAMLプラットフォームでWPFの強力な機能を最大限に活用するには、いくつかの歴史的背景とコア戦略を理解する必要があります。また、WPFテクノロジーを直接使用できるプラットフォームの機能についても詳細に理解する必要があります。
5.1プラットフォーム間の特徴と相違点の理解
**UWPとWinUI 3の違い ** UWPはWindows 10専用のプラットフォームであるため、App Store登録ガイドラインやWinAPIの制限などの理由から、WPFやWinFormsなどの従来のプラットフォームとの互換性が悪い。Win UI 3はUWPのすべての利点を継承しただけでなく、既存の問題点を改善し、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 VSM(VisualStateManager)を最大限活用
由于不是所有平台都可以直接使用WPF的Trigger,所以我们就需要一个替代策略。VisualStateManager(VSM)在解决这个问题上起着核心作用。
VSMは、カスタムコントロールとXAMLとの間の状態処理を最適化し、トリガーの不足を補うためにSilverlight 2.0で導入されました。その後、. NET 4.0では、VSMがWPFにも導入され、Button、CheckBox、DataGrid、Windowなどのすべてのカスタムコントロールの内部設計がTriggerからVSMに変更された。
** メリット ***
- Triggerを直接使用できないプラットフォームでもVSMを使用して同じ機能を実現できます
- UIの状態管理とアニメーションを効果的に実現できる
- VSMで異なるプラットフォームの異なる動作を統合
最終的には、VSMを集中的に使用することで、WPF、Uno Platform Desktop、WinUI3、UWP等のプラットフォーム上で同一のXAMLとCustomControlを構築することができ、ソースコードも完全に共有することができる。
5.3 IValueConverterを活用する
IValueConverter是一个允许在数据绑定时转换值的接口,对于抽象化平台间差异非常有用。
** 戦略的使用**
- Triggerとほぼ同じ機能を実装して代替することができ、シンプルで効果的なソースコードを書く
- Converterを毎回作成する必要があり、再利用性の基準が曖昧であるため、再利用性を過度に追求せず、柔軟に使用することを推奨する
- 再利用性がなくても直感的に使用すること、重要なのは明確な命名によって分岐をできるだけ少なくし、使用に特化すること
** 制限と補足 **
- 仅使用
IValueConverter是有限的 IValueConverter应用于简单转换,复杂场景的管理会带来负担,这时我们应通过VSM解决- 复杂的状态处理最好使用
VisualStateManager
总之,IValueConverter补充了VSM的不足,对于简单直接的转换工作应该直观灵活使用,不要过分追求重用性。
6. 分散プロジェクト管理のためのBootstrapper設計方法論
随着应用程序变得复杂和模块化,初始化过程和依赖管理变得越来越重要。Bootstrapper模式在集中管理这些初始化逻辑方面非常有用。
虽然所有平台都以Application设计为基础,但由于各平台的特性和方式不同,Application设计各不相同。因此,为了在所有平台上保持相同的开发方式,使用Bootstrapper结构设计是非常有效的。
6.1ブートストラップの役割と必要性
** Bootstrの **
- ** Dependency Injection設定 **:DIコンテナを初期化し、必要なサービス、ビュー、およびViewModelを登録します。
- ** ビューとビューモデルの接続の管理 **:依存注入を介してビューを登録し、ビューとViewModel間のマッピングを管理します。
- 集中構成管理:すべての構成はBootstrapperで管理されるため、アプリケーションプロジェクトはロールのみを実行し、残りの機能はプロジェクトの分散とモジュール化によって管理されます。
- さらに、アプリケーションに影響を与えることなく、集中管理プロジェクトを拡張する柔軟性もあります。
** メリット ***
- アプリケーションの初期化ロジックを分離することで、コードの可読性と保守性が向上します。
- プロジェクトの分散とモジュール化により、機能実装は独立して開発できます。
- プラットフォーム間の構造の違いを最小限に抑え、一貫したアーキテクチャを維持する。
6.2 Bootstrapperのデザイン
** サンプルコード **
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();
}
このような抽象化により,管理構造を明示的に強調し,仮想メソッドで時点や順序を制御することができる.これにより、アプリケーションに影響を与えることなく柔軟に拡張し、洗練することができ、さまざまなプラットフォームで一貫した方法で動作します。
7. クロスプラットフォームデスクトップ環境でWPFテクノロジを最大化するための戦略
他のXAMLベースのクロスプラットフォームフレームワークでWPFで使用されているテクニックやパターンを最大限に活用することで、開発効率を向上させることができます。
7.1すべてのプラットフォームで動作するフレームワークの実装

Jamesnet.Core是基于.NET Standard 2.0的框架,允许在WPF、Uno Platform和WinUI 3中实现相同的项目设计。该框架具有以下特点:
- DI設計:ISServiceProviderベースのDIコンテナを利用し、CommunityToolkit.Mvvmと連携して使用できます。
- MVVMブートストラッパー:プロジェクトの初期化と依存性注入を一元管理します。
- ViewとViewModel間の接続管理:レイヤ管理などにより、ViewとViewModelの結合度を低減します。
- すべてのXAMLベースのプラットフォームで動作します。
- リポジトリのソースコードを直接参照し、デバッグ、機能実現、拡張、研究に便利です。
** メリット ***
- WPF、Uno Platform、Win UI 3で開発しても、同じアーキテクチャを維持できます。
- 使用
Uno Platform Desktop可以在macOS和Linux上进行开发和运行。 - 可以使用
JetBrains Rider构建跨平台开发环境。
7.2実际の実装事例
** League of Legendsクライアント·リファクタリング·プロジェクト ** Jamesnet.Coreフレームワークを活用し、WPF、Uno Platform、Win UI 3などの異なるプラットフォームで同じコードベースとアーキテクチャを実装しています。




- WPF版本: GitHub - leagueoflegends-wpf
- Uno Platform版本: GitHub - leagueoflegends-uno
- WinUI 3版本: GitHub - leagueoflegends-winui3
** 戦略的アプローチ **
- **Jamesnet.Coreフレームワークを介して ** プロジェクトデザインの統一性を維持 **。
- DIコンテナとBootstrapperを使用して、ビューとビューモデルを一元管理します。
- 使用
VisualStateManager(VSM)替代Trigger,在不同平台上以相同方式管理UI状态。
** 結果 ***
- ** 97%以上のコード共有 ** により、他のプラットフォームへの拡張の可能性を最大限に高めます。
- さまざまなプラットフォームにわたって一貫したユーザーエクスペリエンスと開発方法論を提供し、テクノロジーの移行を容易にします。
- プロジェクトの分散化、モジュール化、管理の集中化により、開発と保守のコストを大幅に削減します。
- CustomControlのモジュラー開発によりリファクタリングと拡張性が向上し、GPT、ClaudeなどのAIアプリケーションにおいて分散型ビューシステムがより効果的になりました。
結論:結論
WPFのテクノロジーとパターンは依然として強力であり、クロスプラットフォーム開発に適用することで開発効率とコードの再利用が向上します。特にJamesnet.Coreフレームワークを使用して、DIコンテナの集中管理ポリシーとBootstrapperの導入により、ビューとビューモデル間の結合を減らし、保守性を向上させることができます。
また、** Visual State Manager ** と ** IValue Converter ** を積極的に使用することで、プラットフォーム間の差異を最小限に抑え、一貫したデザインを維持できます。これらの戦略により、WPFの基盤を超えたクロスプラットフォーム技術の戦略的拡張が可能になります。
特に、XAML関連DLLは、UWP、WinUI 3、および Uno Platform 間で100%同じで使用されているため、これらのプラットフォーム間の違いはほとんどありません。したがって、WPF開発者にとってUno Platformデスクトップの使用は非常に効果的で戦略的です。これは、WPFからUnoへの変換が数時間で完了し、Win UI 3への変換も非常に簡単だからです。
WPF技術とXAMLベースのフレームワークは今後も進化し続け、クロスプラットフォーム開発に活用することがますます重要になります。開発者はこれらのトレンドを把握し、適切な戦略を立て、高品質なアプリを開発する必要があります。
リファレンス
主な倉庫は
- Jamesnet.Core框架: GitHub - jamesnet.core
- DI、MVVM、Bootstrapperなどの機能を提供するすべてのXAMLベースのプラットフォーム上で動作するフレームワーク。
- ** League of Legendsクライアントリファクタリングプロジェクト **
- WPF版本: GitHub - leagueoflegends-wpf
- Uno Platform版本: GitHub - leagueoflegends-uno
- WinUI 3版本: GitHub - leagueoflegends-winui3
現在更新されているWPFチュートリアルカスタムコントロール
