◇Pile Up◇ --Keenag Blog--

プログラミング備忘録ブログです。C#、WPFの記事が中心となります。

【WPF】ポップアップで入力された値を親画面で受け取る方法

今回は、WPFで親画面でポップアップを出した際に、入力された値を親画面で受け取る方法に ついてサンプルアプリケーションをつくったので、説明してきたいと思います。

各クラスの役割

各クラスの役割はこんな感じです。 なお、いくつかのクラスは省略しています。詳細はサンプルコードを参考にしてください。

クラス名 役割
MainWindow.xaml ポップアップ表示元の親画面のXAML
ChildDialog.xaml 親画面から表示されるポップアップのXAML
InputValueNotification.cs 子から親へ値の橋渡しをするNotificationクラス
MainWindowViewModel.cs ポップアップ表示元の親画面のViewModelクラス
ChildDialogViewModel.cs 親画面から表示されるポップアップのViewModelクラス

MainWindow.xaml

親画面では、ポップアップで入力された文字を表示するTextBoxが用意されています。
また、ポップアップを表示するための「ポップアップ表示」ボタンを配置されています。このボタンを押下することで、prismを使用し、PopupWindowActionでポップアップが表示されます。

<Window x:Class="NotificationSample.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/"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:views="clr-namespace:NotificationSample.Views"
        prism:ViewModelLocator.AutoWireViewModel="True"
        Title="NotificationSample" Height="350" Width="525"
        Background="LightSlateGray">
    <i:Interaction.Triggers>
        <prism:InteractionRequestTrigger SourceObject="{Binding OpenChildDialogRequest}">
            <prism:PopupWindowAction IsModal="True" CenterOverAssociatedObject="True" >
                <prism:PopupWindowAction.WindowContent>
                    <views:ChildDialog />
                </prism:PopupWindowAction.WindowContent>
            </prism:PopupWindowAction>
        </prism:InteractionRequestTrigger>
    </i:Interaction.Triggers>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="100"/>
            <RowDefinition Height="100"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="180"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Label Grid.Row="0"
               Grid.Column="0"
               Content="ポップアップで入力された文字:"
               FontSize="12"
               HorizontalAlignment="Right"
               VerticalAlignment="Bottom"/>
        <TextBox Grid.Row="0"
                 Grid.Column="1"
                 Height="30"
                 HorizontalAlignment="Left"
                 VerticalAlignment="Bottom"
                 Width="200"
                 Text="{Binding OwnerInputValue.Value}"/>
        <Button Grid.Row="1"
                Grid.Column="1"
                Content="ポップアップ表示"
                Width="150"
                Height="50"
                HorizontalAlignment="Left"
                VerticalAlignment="Center"
                Command="{Binding OpenChildDialogCommand}"/>
    </Grid>
</Window>

ChildDialog.xaml

ポップアップ画面では、親画面に引き継ぎたい文字を入力するTextBoxと、ポップアップを閉じ、親画面へ戻る「親画面へ」ボタンが配置されています。

<UserControl x:Class="NotificationSample.Views.ChildDialog"
             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"
             Width="525"
             Height="350"
             Background="LightSlateGray">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="100"/>
            <RowDefinition Height="100"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="180"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Label Grid.Row="0"
               Grid.Column="0"
               Content="親画面に引き継ぐ文字:"
               FontSize="12"
               HorizontalAlignment="Right"
               VerticalAlignment="Bottom"/>
        <TextBox Grid.Row="0"
                 Grid.Column="1"
                 Height="30"
                 HorizontalAlignment="Left"
                 VerticalAlignment="Bottom"
                 Width="200"
                 Text="{Binding ChildInputValue.Value}"/>
        <Button Grid.Row="1"
                Grid.Column="1"
                Content="親画面へ"
                Width="150"
                Height="50"
                HorizontalAlignment="Left"
                VerticalAlignment="Center"
                Command="{Binding NavigateOwnerCommand}"/>
    </Grid>
</UserControl>

InputValueNotification.cs

prismのNotificationクラスを継承したInputValueNotificationクラスには、プロパティにInputValueを定義します。このプロパティにポップアップ内のTextBoxで入力された値を詰め、親画面のViewModelで値を受け取ります。

using Prism.Interactivity.InteractionRequest;

namespace NotificationSample.ViewModels
{
    public class InputValueNotification : Notification
    {
        public string InputValue { get; set; }
    }
}

MainWindowViewModel.cs

OwnerInputValueは、ポップアップで入力された値を表示するために使用するプロパティです。
OpenChildDialogCommandは、親画面で「ポップアップ表示」ボタンを押下した際に呼ばれるCommandです。
OpenChildDialogRequestは、ポップアップの表示をViewに通知するときに使用されます。
OpenChildDialogCommandが実行されると、inputValueNotificationを引数にOpenChildDialogRequestが呼ばれ、 ポップアップが表示されます。
引数で渡したinputValueNotificationが保持するInputValueプロパティがポップアップ側で変更されていたら、OwnerInputValueに、InputValueプロパティの値をセットします。

using Prism.Commands;
using Prism.Interactivity.InteractionRequest;
using Prism.Mvvm;
using Reactive.Bindings;

namespace NotificationSample.ViewModels
{
    public class MainWindowViewModel : BindableBase
    {   
        public ReactiveProperty<string> OwnerInputValue { get; } = new ReactiveProperty<string>();

        public DelegateCommand OpenChildDialogCommand { get; }

        public InteractionRequest<InputValueNotification> OpenChildDialogRequest { get; } = new InteractionRequest<InputValueNotification>();
        
        public MainWindowViewModel()
        {
            OpenChildDialogCommand = new DelegateCommand(() =>
            {
                var inputValueNotification = new InputValueNotification() { Title = "NotificationSample" };
                OpenChildDialogRequest.Raise(inputValueNotification);
                if (inputValueNotification.InputValue != null)
                {
                    OwnerInputValue.Value = inputValueNotification.InputValue;
                }
            });

        }
    }
}

ChildDialogViewModel.cs

ChildInputValueはポップアップのTextBoxのTextにBindingされているプロパティです。 ポップアップで「親画面へ」ボタンが押下された際はNavigateOwnerCommandが実行されます。
NavigateOwnerCommandが実行された際は、ChildInputValueの値をInputValueNotificationのInputValueプロパティに詰め、FinishInteractionでポップアップを閉じます。

using Prism.Commands;
using Prism.Interactivity.InteractionRequest;
using Prism.Mvvm;
using Reactive.Bindings;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NotificationSample.ViewModels
{
    public class ChildDialogViewModel : BindableBase, IInteractionRequestAware
    {
        public INotification Notification { get; set; }
        public Action FinishInteraction { get; set; }
        public ReactiveProperty<string> ChildInputValue { get; } = new ReactiveProperty<string>();


        public DelegateCommand NavigateOwnerCommand => new DelegateCommand(() =>
        {
            ((InputValueNotification)Notification).InputValue = ChildInputValue.Value;
            FinishInteraction();
        });
    }
}

実行結果

実行結果は次のようになります。
ポップアップのTextBoxで入力された値を親画面で受け取れていることが確認できます。

サンプルコード

以下に公開しています。
https://github.com/Keenag/SampleCode/tree/master/NotificationSample