👌

WPFで親Windowと子Windowの連携実装例:犬の管理アプリでの画面閉じたアクションの連携

2025/01/26に公開

ここでは、親Windowと子Windowの画面閉じたアクションを連携する方法を、犬の管理アプリを例にしてシンプルに示します。親ウィンドウが子ウィンドウを開き、子ウィンドウが閉じられたときに親ウィンドウに通知してそのアクションを行う流れを解説します。

以下は、最低限の実装で、親Windowと子Window間の連携を簡潔に示すサンプルです。

フォルダ構成

/DogManagementApp
    ├── /Views
    │   ├── ParentWindow.xaml
    │   ├── ChildWindow.xaml
    ├── /ViewModels
    │   ├── ParentViewModel.cs
    │   ├── ChildViewModel.cs
    ├── /Models
    │   ├── DogModel.cs
    ├── MainWindow.xaml
    ├── App.xaml

1. 親Window(ParentWindow.xaml

親Windowでは、子Windowを開き、子Windowが閉じたタイミングでそのアクションを受け取るようにします。

ParentWindow.xaml

<Window x:Class="DogManagementApp.Views.ParentWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Dog Management" Height="350" Width="525">
    <Grid>
        <Button Content="Open Dog Detail" HorizontalAlignment="Left" VerticalAlignment="Top" Width="120" Height="30" Click="OpenDogDetailWindow"/>
    </Grid>
</Window>

ParentWindow.xaml.cs

using DogManagementApp.ViewModels;
using System.Windows;

namespace DogManagementApp.Views
{
    public partial class ParentWindow : Window
    {
        private readonly ParentViewModel _viewModel;

        public ParentWindow()
        {
            InitializeComponent();
            _viewModel = new ParentViewModel();
            DataContext = _viewModel;
        }

        private void OpenDogDetailWindow(object sender, RoutedEventArgs e)
        {
            var dog = new DogModel { Name = "Buddy", Age = 3 }; // サンプルの犬データ
            var childWindow = new ChildWindow(dog, _viewModel);
            childWindow.Show();
        }
    }
}

2. 子Window(ChildWindow.xaml

子Windowでは、親ViewModelを受け取り、ウィンドウが閉じるときに親に通知します。

ChildWindow.xaml

<Window x:Class="DogManagementApp.Views.ChildWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Dog Detail" Height="250" Width="300">
    <Grid>
        <TextBlock Name="DogNameText" VerticalAlignment="Top" Margin="10,10,10,0"/>
        <Button Content="Close" VerticalAlignment="Bottom" Margin="10" Click="CloseWindow"/>
    </Grid>
</Window>

ChildWindow.xaml.cs

using DogManagementApp.ViewModels;
using DogManagementApp.Models;
using System.Windows;

namespace DogManagementApp.Views
{
    public partial class ChildWindow : Window
    {
        private readonly ParentViewModel _parentViewModel;
        private readonly DogModel _dogModel;

        public ChildWindow(DogModel dogModel, ParentViewModel parentViewModel)
        {
            InitializeComponent();
            _dogModel = dogModel;
            _parentViewModel = parentViewModel;

            DogNameText.Text = $"Dog Name: {_dogModel.Name}, Age: {_dogModel.Age}";
            this.Closing += OnClosing;
        }

        private void OnClosing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            // 親 ViewModel にウィンドウを閉じたことを通知
            _parentViewModel.RemoveChildWindow(this);
        }

        private void CloseWindow(object sender, RoutedEventArgs e)
        {
            this.Close();
        }
    }
}

3. 親ViewModel(ParentViewModel.cs

親ViewModelでは、子ウィンドウの閉じたアクションを受け取り、その後処理を行います。

ParentViewModel.cs

using DogManagementApp.Views;
using System.Collections.Generic;

namespace DogManagementApp.ViewModels
{
    public class ParentViewModel
    {
        private readonly Dictionary<string, ChildWindow> _childWindowMap;

        public ParentViewModel()
        {
            _childWindowMap = new Dictionary<string, ChildWindow>();
        }

        public void RemoveChildWindow(ChildWindow childWindow)
        {
            // 子ウィンドウが閉じられた後の処理
            // 例えば、子ウィンドウをマップから削除する
            var key = childWindow.GetHashCode().ToString();
            if (_childWindowMap.ContainsKey(key))
            {
                _childWindowMap.Remove(key);
            }
        }

        public void AddChildWindow(ChildWindow childWindow)
        {
            var key = childWindow.GetHashCode().ToString();
            if (!_childWindowMap.ContainsKey(key))
            {
                _childWindowMap.Add(key, childWindow);
            }
        }
    }
}

4. DogModel(DogModel.cs

犬のデータを保持するためのシンプルなモデルクラスです。

DogModel.cs

namespace DogManagementApp.Models
{
    public class DogModel
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
}

5. アプリケーションの起動設定(App.xaml

最初に起動するウィンドウを設定します。

App.xaml

<Application x:Class="DogManagementApp.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="Views/ParentWindow.xaml">
    <Application.Resources>
        <!-- Application resource dictionary -->
    </Application.Resources>
</Application>

実行の流れ

  1. 親Window(ParentWindow)を開きます。

    • Open Dog Detail ボタンをクリックすると、犬の詳細を表示する子Window(ChildWindow)が開きます。
  2. 子Window(ChildWindow)で詳細情報を確認します。

    • 犬の名前や年齢を表示します。
    • 「Close」ボタンをクリックすると子ウィンドウが閉じ、親ViewModelにそのアクションが通知されます。
  3. 親ViewModelで子ウィンドウの閉じた通知を受けて処理を行います。

この実装により、親Windowと子Window間の連携が簡潔に行えます。親ウィンドウが子ウィンドウを開き、子ウィンドウが閉じられたときにそのアクションを受け取ることで、親ウィンドウで適切な後処理ができます。

Discussion