【保存版】CommunityToolkit.MvvmでDIを利用した、実務的なWPFでの国際化対応(多言語対応)

DIを使いながら、国際化対応(多言語対応)をしよう 今やグローバル時代!世界を相手にしなければ勝てない! そう、東京弁だけでなく大阪弁、名古屋弁、博多弁など…ごめんなさい調子に乗りました、単純に「日本語」「英語」「ロシア語」対応について語ります。(天丼) 今回は総集編として カップ麺シリーズ:一から学べる、WPFでの多言語対応方法 を、DI込みの記事として公開します。 最初にプロジェクトを作ろう 今回は「WPFアプリケーション」で DIMultiLanguageTest というプロジェクトを作りましょう。フレームワークは「.NET 9.0」を利用します。 プロジェクトに Views と ViewModel フォルダを作ります。 そして開かれた MainWindow.xaml を Views フォルダに移動して、以下のようにします。 <Window x:Class="DIMultiLanguageTest.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:DIMultiLanguageTest" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Title="DIMultiLanguageTest" Width="800" Height="450" mc:Ignorable="d"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Menu> <MenuItem Header="Language"> <MenuItem Command="{Binding ToJapaneseCommand}" Header="Japanese" /> <MenuItem Command="{Binding ToEnglishCommand}" Header="English" /> <MenuItem Command="{Binding ToRussianCommand}" Header="Russian" /> </MenuItem> </Menu> <Button Grid.Row="1" Margin="5" Command="{Binding ExecuteGreetingsCommand}" Content="{Binding Greetings}" /> </Grid> </Window> MainWindow.xaml のフォルダを移動したので、このままでは例外で落ちるため、App.xaml を以下のように書き換えます。 <Application x:Class="DIMultiLanguageTest.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:DIMultiLanguageTest" StartupUri="Views/MainWindow.xaml"> <Application.Resources /> </Application> わかると思いますが、MainWindow.xaml を移動した Views\ を StartupUri に書き加えたわけですね。 ...

2025年04月11日 · (2025年04月30日 更新) · 3 分 · もりゃき

カップ麺シリーズ:CommunityToolkit.Mvvm V8の覚え書き

前提条件 まずは以下の記事内容を踏まえてください。 カップ麺シリーズ:一から学べるWPF における CommunityToolkit.Mvvm(MVVM ToolKit) 覚え書き(1) 簡単な依存性注入とデータバインディング カップ麺シリーズ:一から学べる、WPF における CommunityToolkit.Mvvm(MVVM ToolKit) 覚え書き(2) 依存性注入を利用した簡単なサンプル カップ麺シリーズ:一から学べるWPF における CommunityToolkit.Mvvm(MVVM ToolKit) 覚え書き(3) メッセージングの簡単なサンプル CommunityToolkit.Mvvm V8について 今回、プロジェクト作成は行いません。覚え書き(1)に沿って、最低限コンパイルできる所まで進めてください。 CommunityToolkit.Mvvm V8 は、ざっくり言うと、繰り返しとなる記述を省略できる仕組みが取り入れられています。 [ObservableProperty] 例えば以下のコード private string _username = string.Empty; public string Username { get => _username; set => SetProperty(ref _username, value); } であれば [ObservableProperty] private string _Username = string.Empty; で済みます。 実際はこの時クラスが partial になり、裏側で同等のコードが生成あされています。コンパイルエラーが出ることもあるので、partial クラスになることは最低限覚えておきましょう。 そして、このようなコード private string _username = string.Empty; public string Username { get => _username; set { SetProperty(ref _username, value); NameCommand.NotifyCanExecuteChanged(); } } では、結局従来型の利用方法になるじゃないかと思ったでしょうが、ご安心を。このようにします。 ...

2025年01月12日 · (0001年01月01日 更新) · 3 分 · もりゃき

カップ麺シリーズ:WPFを中心としたMVVM論

はじめに この記事は、そこそこ攻撃的な内容になります。不快に思ったなら、その時点でブラウザバックをしてください。 MVVM とは? MVVMは言うまでもなく Model - View - ViewModel を利用した設計手法で、WPFのみならず .NET MAUI などでも利用されます。 そこで、MVVMを活用するにはどうすればいいのか、という点を中心に語りたいと思います。 まず、論外なのは ViewModel と Model を相互参照するパターンです。 View は ViewModel を知っているが、ViewModel は View を知らない。ViewModel は Model を知っているが、Model は ViewModel を知らない。これが大原則です。 何故かというと、Model とはそれ単体でアプリケーションロジックを全て網羅してるからです。特定の ViewModel に依存してはいけません。 例えば、WPF でアプリケーションを作っている時に、Model は「Modelさえ流用すればコンソールアプリだって作れる」そういう状況が理想です。 …いや、理想っていうか、MVVMってそういうモノなんですけどね? 故に、Model が ViewModel を参照しているサイト…正直私も参照したことがありますが、あの人はおそらく MVVM の根本を分かっていないでしょう。 Model から ViewModel に何かを伝えるためには? Model は ViewModel を知らないのが大原則、ではどうすればいいのか?一応の答えは「イベント通知」になります。 ただし、ある程度の規模になると面倒で複雑で、正直やっていられません。私もサンプルコードを提示できません。 ただし、PrismのEvent AggregatorやCommunityToolkit.MVVMのMessengerといったメッセージングを使えるなら、話はグッと楽になります。 Model から ViewModel にメッセージを飛ばせば良いのです。 メッセージングを利用することで疎結合が守られ、ユニットテストも容易になり、さらにViewModelに依存しない構成を作れます。 さて、ここで読者の皆さんは何か気づきませんか?思い当たる節がなければそれに超したことはありませんが… Model で ObservableCollection を使うのは基本的に誤りです!ObservableCollection は ViewModel から View に更新通知するコレクションですから。 ...

2024年11月23日 · (0001年01月01日 更新) · 1 分 · もりゃき

カップ麺シリーズ:一から学べるWPF における CommunityToolkit.Mvvm(MVVM ToolKit) 覚え書き(3) メッセージングの簡単なサンプル

プロジェクトの準備 この記事では、メッセージングの利用自体は簡単であることを実感してもらうため、 コンソールアプリケーションでの、新規プロジェクトによるサンプルとなります。 Visual Studioから「新しいプロジェクト」で「C#」「Windows」経由で「コンソール アプリ」を選び、 プロジェクト名は「MessagingTest」にして、ソリューションを作成してください。今回はプロジェクト名を変更しても問題ありません。 フレームワークは「.NET 9.0」を使用します。 MVVM Toolkfit の利用準備 ソリューションに対し、Visual Studioのメニュー「ツール」「NuGetパッケージマネージャ」から「ソリューションのNuGetパッケージの管理」を選び、「参照」タブから CommunityToolkit.Mvvm をインストールします。 (1)基本のメッセージング まずは Program.cs を全削除し、以下の内容に置き換えます。 この際、コピペでは身につかないとか言いません。プロジェクトを作って動かせば、見えてくるものもあるでしょう。 using CommunityToolkit.Mvvm.Messaging; namespace MessageingTest { /// <summary> /// 送信クラス(Main含む) /// </summary> public static class Sender { public static void Main() { // 保持する必要はないが、ここでは受信クラスを作る必要がある var _ = new Receiver(); // 弱い参照でのメッセージング var message = new MyMessage("もりゃき", 12); WeakReferenceMessenger.Default.Send(message); // メッセージが出力されるまで待機 Console.ReadKey(); } } /// <summary> /// 受信クラス /// </summary> public class Receiver { public Receiver() { // 弱い参照での受信設定 WeakReferenceMessenger.Default.Register<MyMessage>(this, HandleRegistrationInfo); } // 受信メッセージの処理メソッド private void HandleRegistrationInfo(object recipient, MyMessage message) { Console.WriteLine($"{message.Name} の所持金は {message.Value} 円。"); } } /// <summary> /// メッセージクラス /// </summary> public class MyMessage { public string Name { get; set; } = string.Empty; public int Value { get; set; } public MyMessage() { } public MyMessage(string name, int value) { Name = name; Value = value; } } } こうすると、以下の出力になります。 ...

2024年05月26日 · (2024年11月14日 更新) · 4 分 · もりゃき

カップ麺シリーズ:一から学べる、WPF における CommunityToolkit.Mvvm(MVVM ToolKit) 覚え書き(2) 依存性注入を利用した簡単なサンプル

前提条件 まずは 「WPF における MVVM ToolKit覚え書き(1) 簡単な依存性注入とデータバインディング」 を完読して、プロジェクトを作成してください。 DIを使うための、新しいウィンドウ ViewName を作成する ソリューションエクスプローラーで「Views」フォルダで「追加」から「ウィンドウ(WPF)」を選び、名前に ViewName.xaml と設定してウィンドウを作成します。 そして以下のように置き換えます。 <Window x:Class="NameTest.Views.ViewName" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:NameTest.Views" mc:Ignorable="d" Title="ViewName" Height="450" Width="800"> <Grid VerticalAlignment="Center"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Label Grid.Row="0" Width="300" Height="30" Content="あなたの名前"/> <TextBox Grid.Row="1" Width="300" Height="30" Text="{Binding Name,UpdateSourceTrigger=PropertyChanged}"/> </Grid> </Window> 次に、ViewModels フォルダにおいて「追加」から「クラス」を選び、名前に ViewNameViewModel.cs と設定してクラスを追加します。 内容は無視して以下のように書き換えます。 using CommunityToolkit.Mvvm.ComponentModel; namespace NameTest.ViewModels { public interface IViewNameViewModel; public class ViewNameViewModel : ObservableObject, IViewNameViewModel { private string _name = string.Empty; public string Name { get => _name; set => SetProperty(ref _name, value); } } } そして、このViewModelをDIコンテナに登録します。App.xaml 直下にある App.xaml.cs を開いてください。 ...

2024年05月25日 · (2025年04月20日 更新) · 3 分 · もりゃき

カップ麺シリーズ:一から学べるWPF における CommunityToolkit.Mvvm(MVVM ToolKit) 覚え書き(1) 簡単な依存性注入とデータバインディング

プロジェクトの準備 Visual Studioから新しいプロジェクトで「C#」「Windows」経由で「WPFアプリケーション」を選び、プロジェクト名は「NameTest」にして、ソリューションを作成してください。これでソリューションも NameTest になります。説明通りに動かないことを避けるため、この記事に関しては可能な限りソリューション名を NameTest にしてください。 フレームワークは「.NET 9.0」を使用します。 この「WPF における CommunityToolkit.Mvvm 覚え書き」シリーズは、ある程度のMVVM知識を有していることを前提としております! 簡単に言うとViewは見た目、ViewModelはViewにデータバインディグする関連の処理、Modelはアプリケーションのコアとなる処理群ですね。大規模プロジェクトなら、おそらくModelが一番大きくなります。 MVVM Toolkit の利用準備 ソリューションに対し、Visual Studioのメニュー「ツール」「NuGetパッケージマネージャ」から「ソリューションのNuGetパッケージの管理」を選び、「参照」タブから CommunityToolkit.Mvvm をインストールします。 Microsoft.Extensions.DependencyInjection も同様にインストールします。 もちろん理解している方なら、コマンドからInstall-Package CommunityToolkit.Mvvm等としても構いません。 Ioc - 制御の逆転って? DI(依存性注入)については、簡単に言うと、オブジェクトの生成や依存関係の解決を外部(具体的には後に出てくる App.xaml.cs)に委譲することで、コードの柔軟性とテストの容易さを向上させるパターンです。この記事では、具体的な手順を通じてDIの使い方を学びます。 何より大切なのは、自分でソリューションを作り、手を動かすことです。コピペしても何も習得できず、応用が利きません。 App.xaml の書き換え まずは MVVM としてのスタンダードとして、プロジェクト直下に [追加] から [新しいフォルダ] を利用して Views 、ViewModels そして Models フォルダを作ります、(今回は Models 使わないので省いていいですけど、一般的な構成として覚えておいてください、すなわち大規模アプリケーション開発に直接アドバイスする記事ではありません)。 プロジェクト直下にある MainWindow.xaml を Views にドラッグドロップで移動します。移動時、名前空間も調整してください。 そして App.xaml を以下のように調整してください。 <Application x:Class="NameTest.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:NameTest" StartupUri="MainWindow.xaml"> <Application.Resources> </Application.Resources> </Application> から <Application x:Class="NameTest.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:NameTest" StartupUri="Views/MainWindow.xaml"> <!-- MainWindowをViewsフォルダに移動したからそれを反映 --> <Application.Resources> </Application.Resources> </Application> と変更します。StartupUri の行に Views フォルダを追加するだけです(コメントは不要です)。 ...

2024年05月20日 · (2024年11月14日 更新) · 3 分 · もりゃき

WPFにおけるPrism集中講座(7) ラストスパート

22-ConfirmCancelNavigation Descriptionには Use the IConfirmNavigationReqest interface to confirm or cancel navigation とあります。 実際に実行したら、ViewA と ViewB を切り替えるボタンがありますが… ViewA から ViewB に切り替える時にはメッセージボックスが出るのに、 ViewB から ViewA に切り替える時にメッセージボックスが出ない、え?これ欠陥品じゃないの? ああ、ソースコードを読んだら納得しました。 ModuleA 内の ViewModels\ViewAViewModel.cs using System.Windows; namespace ModuleA.ViewModels { public class ViewAViewModel : BindableBase, IConfirmNavigationRequest { public ViewAViewModel() { } public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback) { bool result = true; if (MessageBox.Show("Do you to navigate?", "Navigate?", MessageBoxButton.YesNo) == MessageBoxResult.No) result = false; continuationCallback(result); } public bool IsNavigationTarget(NavigationContext navigationContext) { return true; } public void OnNavigatedFrom(NavigationContext navigationContext) { } public void OnNavigatedTo(NavigationContext navigationContext) { } } } ModuleA 内の ViewModels\ViewBViewModel.cs namespace ModuleA.ViewModels { public class ViewBViewModel : BindableBase { public ViewBViewModel() { } } } っていうか、訳がわからないですね? ...

2025年01月21日 · (0001年01月01日 更新) · 4 分 · もりゃき

WPFにおけるPrism集中講座番外編:16-RegionContextをCommunityToolkit.Mvvmでリファクタリングする

まずは下準備! はーい、またやってきました!CommunityToolkit.Mvvm大好きの、もりゃきお姉さんだよ! 今回はパパも、基本的な画面構成以外は好きにやって良いとお許しがでましたので、バンバン変えていきますよ! プロジェクトを作りましょう。 Visual Studioで「WPFアプリケーション」を選んで、ソリューション名は「BusinessPersonsSample」、フレームワークは「.NET 9」選択ね! 次に、NuGet経由で「CommunityToolkit.Mvvm」と「Microsoft.Extensions.DependencyInjection」をいつもの通りにインストールしましょうね! 繰り返すけど、CommunityToolkit.Mvvm V8 を使うから、エラーが出たらとりあえずリビルドしてね、お姉さんとの約束よ! DI の設定よ はい、これを App.xaml.cs に適切にコピペしちゃいましょう! public partial class App : Application { /// <summary> /// サービスの登録をします /// </summary> public App() { Services = ConfigureServices(); Ioc.Default.ConfigureServices(Services); } /// <summary> /// 現在の App インスタンスを取得します /// </summary> public new static App Current => (App)Application.Current; /// <summary> /// サービスプロバイダです /// </summary> public IServiceProvider Services { get; } /// <summary> /// サービスを登録します /// </summary> /// <returns></returns> private static ServiceProvider ConfigureServices() { var services = new ServiceCollection(); services.AddSingleton<IMessenger, WeakReferenceMessenger>(); services.AddSingleton<IMainWindowViewModel, MainWindowViewModel>(); return services.BuildServiceProvider(); } } フォルダの作成と準備 まずはプロジェクトに Views と ViewModels、Models フォルダを作るわよ。 ...

2025年01月20日 · (0001年01月01日 更新) · 3 分 · もりゃき

WPFにおけるPrism集中講座(6) EventAggregatorとregionを使う

14-UsingEventAggregator Description には Using the IEventAggregator とあります。 まんま過すぎですね。 動かしてみると、TextBox に入力した内容を「Send Message」で送ると、 ListBox に追加されるというサンプルのようです。 UsingEventAggregator 内の App.xaml.cs using System.Windows; using UsingEventAggregator.Views; namespace UsingEventAggregator { /// <summary> /// Interaction logic for App.xaml /// </summary> public partial class App : PrismApplication { protected override Window CreateShell() { return Container.Resolve<MainWindow>(); } protected override void RegisterTypes(IContainerRegistry containerRegistry) { } protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog) { moduleCatalog.AddModule<ModuleA.ModuleAModule>(); moduleCatalog.AddModule<ModuleB.ModuleBModule>(); } } } UsingEventAggregator 内の Views\MainWindow.xaml <Window x:Class="UsingEventAggregator.Views.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:prism="http://prismlibrary.com/" Title="{Binding Title}" Width="525" Height="350" prism:ViewModelLocator.AutoWireViewModel="True"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition /> </Grid.ColumnDefinitions> <ContentControl prism:RegionManager.RegionName="LeftRegion" /> <ContentControl Grid.Column="1" prism:RegionManagerRegionName="RightRegion" /> </Grid> </Window> UsingEventAggregator 内の ViewsModels\MainWindowViewModel.cs namespace UsingEventAggregator.ViewModels { public class MainWindowViewModel : BindableBase { private string _title = "Prism Unity Application"; public string Title { get { return _title; } set { SetProperty(ref _title, value); } } public MainWindowViewModel() { } } } ModuleA プロジェクトと ModuleB プロジェクトを ContentControl で読み込んでいるようです。 ...

2025年01月19日 · (0001年01月01日 更新) · 11 分 · もりゃき

WPFにおけるPrism集中講座番外編:Prismの複雑怪奇なCommand周りをCommunityToolkit.Mvvmで実装する

まずはプロジェクトの作成と整備ね さあ、CommunityToolkit.Mvvm 大好きな、もりゃきお姉ちゃんがやってきましたよ! ますは、サクサクプロジェクトを作りましょう。 Visual Studioで「WPFアプリケーション」を選んで、ソリューション名は「TabCommandSample」、フレームワークは「.NET 9」選択でいいでしょう! 次に、NuGet経由で「CommunityToolkit.Mvvm」と「Microsoft.Extensions.DependencyInjection」をいつもの通りにインストールしましょうね! あ、CommunityToolkit.Mvvm V8 を使うから、エラーが出たらとりあえずリビルドしてね、お姉さんとの約束よ! 次は DI の設定よ!こんなの App.xaml.cs に書くだけなんだから、たくさんアプリケーション作る人はコピペできるようにしとくのが賢い子☆ public partial class App : Application { /// <summary> /// サービスの登録をします /// </summary> public App() { Services = ConfigureServices(); Ioc.Default.ConfigureServices(Services); } /// <summary> /// 現在の App インスタンスを取得します /// </summary> public new static App Current => (App)Application.Current; /// <summary> /// サービスプロバイダです /// </summary> public IServiceProvider Services { get; } /// <summary> /// サービスを登録します /// </summary> /// <returns></returns> private static ServiceProvider ConfigureServices() { var services = new ServiceCollection(); services.AddSingleton<IMessenger, WeakReferenceMessenger>(); services.AddSingleton<IMainWindowViewModel, MainWindowViewModel>(); return services.BuildServiceProvider(); } } 次はエラーが出た MainWindowViewModel の設定だけど、まとめてやっちゃうわよ! プロジェクトにとりあえず Views と ViewModels フォルダを作って MainWindow.xaml を Views に移動、名前空間も手動作業含めて調整。 ...

2025年01月18日 · (0001年01月01日 更新) · 4 分 · もりゃき