RegionManagerを使ったMainWindowへの他のViewの表示(Parameter付き)

1. UserControlViewプロジェクトに対し、MainWindowからViewにパラメータを渡して表示する機能を追加していきます。(リポジトリでは、変更済みのプロジェクトの名称をNavigateToViewWithParametersとしています。)

以降の手順の準備として、UserControlViewプロジェクトと構成が同じでプロジェクト名がNavigateToViewWithParametersのプロジェクトを作成しておきます。

2. 作成したプロジェクトのViewsフォルダを右クリックし、新しい項目を追加します。

3. 新しい項目の追加でPrism UserControl (WPF)を選択します。追加する項目の名前はViewWithParametersViewにしました。この画面で追加をクリックします。

4. NavigateToViewWithParametersプロジェクトにViews/ViewWithParametersView.xaml(およびViewWithParametersView.xaml.cs)とViewModels/ViewWithParametersViewModel.csが追加されます。

5. Viewへのパラメータ渡しとは関係ありませんが、Material Design In XAMLのAccentのカラーを下記のApp.xamlのようにLightGreenからYellowに変更しました。変更した行をハイライト表示しています。

<prism:PrismApplication x:Class="NavigateToViewWithParameters.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:NavigateToViewWithParameters"
             xmlns:prism="http://prismlibrary.com/" >
    <Application.Resources>

        <ResourceDictionary>

            <ResourceDictionary.MergedDictionaries>

                <!-- MahApps -->
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
                <!-- Theme setting -->
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/Light.Green.xaml" />

                <!-- Material Design -->
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.LightGreen.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Yellow.xaml" />

                <!-- Material Design: MahApps Compatibility -->
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.MahApps;component/Themes/MaterialDesignTheme.MahApps.Fonts.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.MahApps;component/Themes/MaterialDesignTheme.MahApps.Flyout.xaml" />

            </ResourceDictionary.MergedDictionaries>

            <!-- MahApps Brushes -->
            <SolidColorBrush x:Key="HighlightBrush" Color="{DynamicResource Primary700}"/>
            <SolidColorBrush x:Key="AccentBaseColorBrush" Color="{DynamicResource Primary600}" />
            <SolidColorBrush x:Key="AccentColorBrush" Color="{DynamicResource Primary500}"/>
            <SolidColorBrush x:Key="AccentColorBrush2" Color="{DynamicResource Primary400}"/>
            <SolidColorBrush x:Key="AccentColorBrush3" Color="{DynamicResource Primary300}"/>
            <SolidColorBrush x:Key="AccentColorBrush4" Color="{DynamicResource Primary200}"/>
            <SolidColorBrush x:Key="WindowTitleColorBrush" Color="{DynamicResource Primary700}"/>
            <SolidColorBrush x:Key="AccentSelectedColorBrush" Color="{DynamicResource Primary500Foreground}"/>
            <LinearGradientBrush x:Key="ProgressBrush" EndPoint="0.001,0.5" StartPoint="1.002,0.5">
                <GradientStop Color="{DynamicResource Primary700}" Offset="0"/>
                <GradientStop Color="{DynamicResource Primary300}" Offset="1"/>
            </LinearGradientBrush>
            <SolidColorBrush x:Key="CheckmarkFill" Color="{DynamicResource Primary500}"/>
            <SolidColorBrush x:Key="RightArrowFill" Color="{DynamicResource Primary500}"/>
            <SolidColorBrush x:Key="IdealForegroundColorBrush" Color="{DynamicResource Primary500Foreground}"/>
            <SolidColorBrush x:Key="IdealForegroundDisabledBrush" Color="{DynamicResource Primary500}" Opacity="0.4"/>
            <SolidColorBrush x:Key="MahApps.Metro.Brushes.ToggleSwitchButton.OnSwitchBrush.Win10" Color="{DynamicResource Primary500}" />
            <SolidColorBrush x:Key="MahApps.Metro.Brushes.ToggleSwitchButton.OnSwitchMouseOverBrush.Win10" Color="{DynamicResource Primary400}" />
            <SolidColorBrush x:Key="MahApps.Metro.Brushes.ToggleSwitchButton.ThumbIndicatorCheckedBrush.Win10" Color="{DynamicResource Primary500Foreground}" />

        </ResourceDictionary>

    </Application.Resources>
</prism:PrismApplication>

6. デザインの変更とViewへのParameter渡しの準備のため、Views/MainWindow.xamlを下記のように変更します。

<metro:MetroWindow x:Class="NavigateToViewWithParameters.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:metro="http://metro.mahapps.com/winfx/xaml/controls"
        xmlns:prism="http://prismlibrary.com/"
        prism:ViewModelLocator.AutoWireViewModel="True"
        Title="{Binding Title}" Height="350" Width="525" >
    <StackPanel>
        <TextBox FontSize="16" Text="{Binding DateTimeText}" />
        <Button Content="Update Time" Command="{Binding DateTimeUpdateButton}"/>
        <UniformGrid Columns="2">
            <Button Content="Show Huge Label View" Command="{Binding ShowHugeLabelButton}"
                    Style="{StaticResource MaterialDesignRaisedLightButton}"/>
            <Button Content="Show View with Parameters" Command="{Binding ShowViewWithParametersButton}"
                    Style="{StaticResource MaterialDesignRaisedSecondaryButton}"/>
        </UniformGrid>
        <ContentControl prism:RegionManager.RegionName="ContentRegion" />
    </StackPanel>
</metro:MetroWindow>

一番外側のGridタグを外し、全体をStackPanel内に配置するようにしました。StackPanel内の三行目にコラム数が2のUniformGridを用意し、同じ大きさのボタンを左右に並べて配置するようにしました。

ViewWithParametersViewに渡す変数をDateTimeLabelからDateTimeTextに変更しました。DateTimeTextの文字列をユーザーが書き換えられるよう、LabelからTextBoxに変更しました。

Show Huge Label ViewボタンのStyleをStyle=”{StaticResource MaterialDesignRaisedLightButton}”のように指定しました。デフォルトのButtonより少し薄い配色のボタンになっています。また、Show View with ParametersボタンのStyleをStyle=”{StaticResource MaterialDesignRaisedSecondaryButton}”としました。アクセントとして指定した黄色のボタンになっています。

7. ViewWithParametersViewをMainWindowViewModel.csからRequestNavigateメソッドで表示できるようにするため、App.xaml.csにハイライトした行を追加します。

using NavigateToViewWithParameters.Views;
using Prism.Ioc;
using System.Windows;

namespace NavigateToViewWithParameters
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App
    {
        protected override Window CreateShell()
        {
            return Container.Resolve<MainWindow>();
        }

        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
            containerRegistry.RegisterForNavigation<HugeLabelView>();
            containerRegistry.RegisterForNavigation<ViewWithParametersView>();
        }
    }
}

8. MainWindowViewModel.csの下記のハイライトした行を変更または追加します。

using Prism.Commands;
using Prism.Mvvm;
using Prism.Regions;
using NavigateToViewWithParameters.Views;

namespace NavigateToViewWithParameters.ViewModels
{
    public class MainWindowViewModel : BindableBase
    {
        private readonly IRegionManager _regionManager;

        private string _title = "Prism NavigateToViewWithParameters";
        public string Title
        {
            get { return _title; }
            set { SetProperty(ref _title, value); }
        }

        private string _dateTimeText = System.DateTime.Now.ToString();
        public string DateTimeText
        {
            get { return _dateTimeText; }
            set { SetProperty(ref _dateTimeText, value); }
        }

        public DelegateCommand DateTimeUpdateButton { get; }
        public DelegateCommand ShowHugeLabelButton { get; }
        public DelegateCommand ShowViewWithParametersButton { get; }

        public MainWindowViewModel(IRegionManager regionManager)
        {
            DateTimeUpdateButton = new DelegateCommand(DateTimeUpdateButtonExecute);
            ShowHugeLabelButton = new DelegateCommand(ShowHugeLabelButtonExecute);
            ShowViewWithParametersButton = new DelegateCommand(ShowViewWithParametersButtonExecute);
            _regionManager = regionManager;
        }

        private void DateTimeUpdateButtonExecute()
        {
            DateTimeText = System.DateTime.Now.ToString();
        }

        private void ShowHugeLabelButtonExecute()
        {
            _regionManager.RequestNavigate("ContentRegion", nameof(HugeLabelView));
        }

        private void ShowViewWithParametersButtonExecute()
        {
            var parameters = new NavigationParameters();
            parameters.Add(nameof(ViewWithParametersViewModel.ParameterText), DateTimeText);
            _regionManager.RequestNavigate("ContentRegion", nameof(ViewWithParametersView), parameters);
        }
    }
}

19-24行目では変数名の末尾をLabelからTextに変更しています。MainWindow.xamlでLabelからTextBoxに変更したため、変更後のプログラムではDateTimeTextに現在時刻をセットして表示するだけでなく、TextBoxの内容を編集することもできます。

28行目でViewWithParametersViewを表示するボタンのCommandにバインドするDelegateCommandを用意しています。34行目でボタンが押されたときに呼び出されるメソッドShowViewWithParametersButtonExecuteをパラメータとしてこのDelegateCommandをインスタンス化しています。

48-53行目がメソッドShowViewWithParametersButtonExecuteです。50行目でパラメータを格納するNavigationParameters型のparametersオブジェクトを生成しています。51行目でparametersオブジェクトにnameof(ViewWithParametersViewModel.ParameterText)をKey、DateTimeTextをValueとするパラメータを格納しています。52行目でRequestNavigateを呼んでViewWithParametersViewをMainWindow.xamlのContentControlに表示します。このとき、第3引数としてparametersオブジェクトを与え、パラメータをViewWithParametersViewに渡しています。

9. ViewWithParametersViewModel.csの下記のハイライトした行を変更または追加します。

using Prism.Mvvm;
using Prism.Regions;

namespace NavigateToViewWithParameters.ViewModels
{
    public class ViewWithParametersViewModel : BindableBase, INavigationAware
    {
        public ViewWithParametersViewModel()
        {

        }

        private string _parameterText = string.Empty;
        public string ParameterText
        {
            get { return _parameterText; }
            set { SetProperty(ref _parameterText, value); }
        }


        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
            return true;
        }

        public void OnNavigatedFrom(NavigationContext navigationContext)
        {

        }

        public void OnNavigatedTo(NavigationContext navigationContext)
        {
            ParameterText = navigationContext.Parameters.GetValue<string>(nameof(ParameterText));
        }
    }
}

MainWindowViewModelのメソッド_regionManager.RequestNavigate(“ContentRegion”, nameof(ViewWithParametersView), parameters)で渡された引数parametersを受け取ることができるようにするため、6行目でインターフェイスINavigationAwareを実装しています。

21-24, 26-29, 31-34行目でINavigationAwareの3つのメソッドを実装しています。

OnNavigatedToメソッドはRequestNavigateでViewが表示されるときに実行されるメソッドです。33行目のようにキーをnameof(ParameterText)として、string型のValueを取得してParameterTextにセットしています。MainWindowViewModel.csの51-52行目でparametersインスタンスにセットしたKey、Value形式のパラメータのValueを取得しています。

IsNavigationTargetメソッドはViewが表示されなくなった後も以前の値を保持するか否かをbool値で返します。今回の実装の場合、どちらでも結果は変わりませんが、値を保持するtrueを返すことにしました。

OnNavigatedFromはViewが表示されなくなる直前に実行されるメソッドです。Viewの終了処理等を記述します。今回の実装では何も行いません。

13-18行目はViewWithParametersViewが受け取ったパラメータ文字列を格納する変数とプロパティを用意しています。プロパティParameterTextをViewWithParametersView.xamlでTextBlockのTextとバインドし、受け取ったパラメータ文字列をViewWithParametersViewに表示するようにします。

10. ViewWithParametersView.xamlに下記のハイライトした行を追加します。

<UserControl x:Class="NavigateToViewWithParameters.Views.ViewWithParametersView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:prism="http://prismlibrary.com/"             
             prism:ViewModelLocator.AutoWireViewModel="True">
    <Grid>
        <TextBlock Text="{Binding ParameterText}" FontSize="50"
                   Foreground="{StaticResource AccentColorBrush4}"
                   TextWrapping="Wrap"/>
    </Grid>
</UserControl>
  • プロパティParameterTextをTextBlockのTextとバインドし、ParameterTextの値が表示されるようにしています。
  • Foreground=”{StaticResource AccentColorBrush4}”で表示する文字の色を指定しています。
  • TextWrapping=”Wrap”で、文字列がViewからはみ出すときは折り返すようにしています。
  • FontSize=”50″でフォントサイズを指定しています。

11. プログラムをデバッグ実行し、Show Huge Label Viewボタンをクリックすると下記のように表示されます。

12. Show View with Parametersボタンをクリックすると下記のように表示されます。DateTimeTextの文字列がMainWindowからViewWithParametersViewに渡され、ViewWithParametersView内に表示されます。

13. 時刻を表示しているTextBoxに適当な文字列を追加します。

14. もう一度Show View with Parametersボタンをクリックすると下記のように表示されます。文字列を追加されたDateTimeTextの文字列がMainWindowからViewWithParametersViewに渡され、ViewWithParametersView内に表示されます。