Prism+ReactivePropertyで簡単WPFアプリケーション開発(その2)


前回は、簡単にMainWindowでのV⇔VM連携のみでしたが、今回は少し拡張して任意のユーザーコントロールを作成して、それに付随するViewModelとMainWindowのViewModelを連携してみます。

ユーザーコントロールとそのViewModelを作る

適当にTextBoxを置いた、UserControlを作成します。

Sample.xaml
<UserControl
    x:Class="WpfApp1.Views.Sample"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:local="clr-namespace:WpfApp1.Views"
    xmlns:prism="http://prismlibrary.com/"
    prism:ViewModelLocator.AutoWireViewModel="True" 
    mc:Ignorable="d" 
    d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <TextBox Text="{Binding Path=Input.Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
    </Grid>
</UserControl>

それと連携するViewModelを作成します。

SampleViewModel.cs

    using Reactive.Bindings;
    using Reactive.Bindings.Extensions;

    public class SampleViewModel: ViewModelBase
    {
        public SampleViewModel()
        {
            // ユーザーからの入力を受けるプロパティ
            this.Input = new ReactiveProperty<string>().AddTo(this.disposedValue);
        }

        public ReactiveProperty<string> Input { get; }
    }

Appにクラスを登録する

App.cs
protected override void ConfigureViewModelLocator()
{
    base.ConfigureViewModelLocator();
    ViewModelLocationProvider.Register<Sample, SampleViewModel>();
    ViewModelLocationProvider.Register<MainWindow, MainWindowViewModel>();
}

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
    base.ConfigureViewModelLocator();
    containerRegistry.RegisterSingleton<SampleViewModel>();
}

MainWindowへRegionNameを登録する

ウィンドウにLoadイベントをして、ReaginNameを登録して、コントロールを配置します。

MainWindow.xaml
<metro:MetroWindow 
    ...
    Loaded="MetroWindow_Loaded"
    Title="MainWindow" Height="250" Width="400"
    >
    ...
    <!-- コントロールを配置する -->
    <ContentControl prism:RegionManager.RegionName="Sample" />
MainWindow.xaml.cs

    using MahApps.Metro.Controls;
    using Prism.Ioc;
    using Prism.Regions;
    using Unity;

    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : MetroWindow
    {
        [Dependency]
        public IContainerExtension ContainerExtension { get; set; }

        [Dependency]
        public IRegionManager RegionManager { get; set; }

        public MainWindow()
        {
            InitializeComponent();
        }

        private void MetroWindow_Loaded(object sender, RoutedEventArgs e)
        {
            // Regionを登録する。
            RegionManager.AddToRegion("Sample", ContainerExtension.Resolve<Sample>());
        }
    }

ViewModel間連携

MainWindowViewModel.cs

    using System.Threading.Tasks;
    using Reactive.Bindings;
    using Reactive.Bindings.Extensions;

    public class MainWindowViewModel : ViewModelBase
    {
        public MainWindowViewModel(SampleViewModel sampleViewModel) : base()
        {

            // テキスト
            this.Text = new ReactiveProperty<string>("ボタンを押してみてください。")
                .AddTo(this.disposedValue);

            // ボタン
            this.RunCommand = new AsyncReactiveCommand()
            .WithSubscribe(async () =>
            {
                await Task.Run(() =>
                {
                    // SampleViewModelのプロパティを参照する。
                    this.Text.Value = sampleViewModel.Input.Value;
                });
            })
            .AddTo(this.disposedValue);
        }

        public ReactiveProperty<string> Text { get; }

        public AsyncReactiveCommand RunCommand { get; }
    }

これで、準備完了。

デバッグ

デバッグして、試してみます。
TextBoxに何か入力して、、、

ボタンを押すと
↓↓↓

SampleViewModelの値がMainVindowViewModelのプロパティに反映されました。
これでOKです。