📖
WPFで子ViewにBindingを行うと子のDataContextを参照する
親Viewが子のViewを含んでいる。
それぞれがそれぞれのViewModelを生成している。
という状況です。
コードにて状況説明すると
// ChildView.xaml
<UserControl ...省略...>
<UserControl.DataContext>
<local:ChildViewModel/>
</UserControl.DataContext>
<Grid>
<Button Content="Child"
Visibility="{Binding Visibility, Mode=OneWay}"/>
</Grid>
</UserControl>
// ChildViewModel.cs
using System.Windows;
namespace ChildViewModelTest
{
internal class ChildViewModel : ViewModelBase
{
public Visibility Visibility => Visibility.Visible;
}
}
// MainWindow.xaml
<Window ...省略...>
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<local:ChildView Visibility="{Binding Visibility, Mode=OneWay}"/>
</Grid>
</Window>
// MainWindowViewModel.cs
using System.Windows;
namespace ChildViewModelTest
{
internal class MainWindowViewModel : ViewModelBase
{
public Visibility Visibility => Visibility.Visible;
}
}
こんな感じ。
Modelが作られていないとか、その変数なに?とかはここでは些末な問題なのでご容赦ください。
ViewModelBaseはDataContextに設定するためのINotifyPropertyChangedを実装したものと考えてください。
さてここで、親Viewから子ViewのVisibilityを制御したいと思ったので、以下変更を加えました。
// MainWindowViewModel.cs
internal class MainWindowViewModel : ViewModelBase
{
// public Visibility Visibility => Visibility.Visible;
public Visibility Visibility => Visibility.Hidden;
}
これでWindowを開いた時にChildViewは見えなくなるだろう、と思いましたが、
実行してみると見た目上に変化なし。
原因はタイトルにある通りですが、
どうやら、子ViewへのBindingは子のDataContextのプロパティが適用されるようです。
この場合はChildViewModel.Visibilityを参照しているので、何も変わらなかったと。
VisualStudio使ってて、MainWindow.xaml上でBindingしているVisibilityの定義に移動する(F12)と自分のViewModelに飛ぶので、非常に混乱しました。たまたま同じ名前のプロパティがあったので、余計に紛らわしかったです。
仕様なのか、どうしてこうなるのか、よく分かっていませんが、
今回の目的としてはVisibilityの制御なので、親要素を作ってそちらにBindingすることで事なきを得ました。
<Window ...省略...>
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<Grid Visibility="{Binding Visibility, Mode=OneWay}"> <!-- 親要素で制御 -->
<local:ChildView />
</Grid>
</Grid>
</Window>
Discussion