LoginSignup
10
12

More than 5 years have passed since last update.

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

Posted at

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

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

XAML の記述

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

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>
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」というテキストが交互に設定され、
それがラベル、テキストボックスの双方に表示される、という仕様になっています。

注目するのはここです。

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

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

C# コードの記述

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

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();
        }
    }
}
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 は自分の更新通知を出しているだけです。

10
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
12