子の ViewModel のプロパティの更新通知を受け取って、親の View を更新する方法

ViewModel が子として別の ViewModel を持っているパターンというのは結構よくあることだと思いますが、
その際、子の ViewModel のプロパティの更新通知を受け取って親の View を更新したいということもあると思います。
（例えば、リストビューの要素数をステータスバーに表示したい、など。）

これを、できれば XAML の指定のみでやりたいと思って調べて、実際にやってみました。

# XAML の記述
まずは、XAML の記述からです。

```xml:MainWindow.xaml
<Window x:Class="WPF_MVVM.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WPF_MVVM"
        xmlns:local_vm="clr-namespace:WPF_MVVM.ViewModels"
        xmlns:local_v="clr-namespace:WPF_MVVM.Views"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local_vm:MainViewModel />
    </Window.DataContext>
    <Grid>
        <Label x:Name="label" Content="{Binding TextBoxViewModel.Text}" HorizontalAlignment="Left" Margin="39,31,0,0" VerticalAlignment="Top"/>
        <local_v:TextBoxView x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="39,82,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" DataContext="{Binding TextBoxViewModel}"/>
        <Button x:Name="button" Content="Button" HorizontalAlignment="Left" Margin="53,149,0,0" VerticalAlignment="Top" Width="75" Command="{Binding ButtonCommand}" />
    </Grid>
</Window>
```

```xml:TextBoxView.xaml
<TextBox x:Class="WPF_MVVM.Views.TextBoxView"
             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:WPF_MVVM.Views"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"
             Text="{Binding Text}">
</TextBox>
```

MainWindow.xaml がウィンドウの XAML、
TextBoxView.xaml が配置しているテキストボックスの XAML です。

ウィンドウには

* ラベル
* テキストボックス
* ボタン

を配置しています。

ラベル、テキストボックスそれぞれに **TextBoxViewModel::Text** をバインドしています。
ボタンを押すたびに **TextBoxViewModel::Text** に**「True」「False」**というテキストが交互に設定され、
それがラベル、テキストボックスの双方に表示される、という仕様になっています。

注目するのはここです。

```xml
<local_v:TextBoxView ... DataContext="{Binding TextBoxViewModel}"/>
```

これは、テキストボックスの DataContext に **Window.DataContext.TextBoxViewModel** をバインドしています。
こうすることで、子として持っている ViewModel と親の View で配置されているコントロールの DataContext を XAML のみでバインドできます。

# C# コードの記述
次に、C# コードの記述です。実装には Livet を使用しています。

```csharp:MainViewModel.cs
using Livet;
using Livet.Commands;

namespace WPF_MVVM.ViewModels
{
    // ウィンドウの ViewModel
    class MainViewModel : ViewModel
    {
        //  ボタンの Command とバインドしているプロパティ
        public ViewModelCommand ButtonCommand
        {
            get
            {
                return _ButtonCommand ?? (_ButtonCommand = new ViewModelCommand(ClickButton));
            }
        }
        private ViewModelCommand _ButtonCommand;

        //  テキストボックスの ViewModel
        public TextBoxViewModel TextBoxViewModel
        {
            get
            {
                return _TextBoxViewModel;
            }
            set
            {
                _TextBoxViewModel = value;
            }
        }
        public TextBoxViewModel _TextBoxViewModel;

        //  コンストラクタ
        public MainViewModel()
        {
            _TextBoxViewModel = new TextBoxViewModel();
        }

        //  テキスト変更用のフラグ
        private bool _Flag = false;

        //  ボタンを押した時に実行される処理
        private void ClickButton()
        {
            _Flag = !_Flag;
            _TextBoxViewModel.Text = _Flag.ToString();
        }
    }
}
```

```csharp:TextBoxViewModel.cs
using Livet;

namespace WPF_MVVM.ViewModels
{
    // テキストボックスの ViewModel
    class TextBoxViewModel : ViewModel
    {
        // テキストボックスに表示するテキスト
        public string Text
        {
            get
            {
                return _Text;
            }
            set
            {
                _Text = value;
                RaisePropertyChanged(nameof(Text));
            }
        }
        private string _Text;
    }
}
```

MainWindowView.cs がウィンドウの ViewModel、
TextBoxViewModel.cs が配置しているテキストボックスの ViewModel です。

データバインドに使用しているプロパティ TextBoxViewModel::Text は自分の更新通知を出しているだけです。