UserControl と DataContext
◆ Binding のデフォルトソースオブジェクトはそのプロパティの DataContext
◆ DataContext は設定されていないと親要素の値を設定する
◆ 親がなければルートまで親をみていく
◆ 実装的には下から上をみるんじゃなくて 最初に上から下へ落としていくだけかな?
◆ UserControl 内部で this.DataContext を設定すると UserControl を使う Window の DataContext に Binding できなくなる
◆ DataContext は設定されていないと親要素の値を設定する
◆ 親がなければルートまで親をみていく
◆ 実装的には下から上をみるんじゃなくて 最初に上から下へ落としていくだけかな?
◆ UserControl 内部で this.DataContext を設定すると UserControl を使う Window の DataContext に Binding できなくなる
よく Window で
という風に書くと思います
(XAML でやる派もいるみたい)
注目するのは this.DataContext を設定してるところ
UserControl でも同じようにしてしまいがちですが バグのもとです
Label に DataContext プロパティが設定されていない場合は DataContext に親要素の DataContext を設定します
親を辿っていくので 最終的に Window の DataContext が Window 内全部の要素の DataContext として使えるというわけです
上の XAML で適当に Window.DataContext を設定すれば Grid, StackPanel, Button, Label の DataContext を == でチェックするとすべて true で Window.DataContext の値になっています
Window とは違う Datacontext はButton に設定するとこうなります
button の子要素になる label も button に設定された BindingData2 が DataContext です
button より親の要素は Window に設定された BindingData1 が DataContext です
のように Window の中に存在します
UserControl を作るときに UserControl の中で DataContext を設定していた場合は それが DataContext になっているので Window の DataContext ではなくなってしまいます
WindowDataContext のつもりで value="{Binding val"} を書いていても DataContext は UserControlDataContext のものになっています
わかりづらくて バグのもとなので UserControl では DataContext をソースにする Binding を使わないか ルートになる Grid とか Stackpanel とかに名前をつけてそこに Binding するのが安全です
こんな感じ
public MainWindow()
{
this.DataContext = new BindingData();
}
{
this.DataContext = new BindingData();
}
という風に書くと思います
(XAML でやる派もいるみたい)
注目するのは this.DataContext を設定してるところ
UserControl でも同じようにしてしまいがちですが バグのもとです
DataContext
DataContext の仕組みですが<Grid>
<StackPanel>
<Button>
<Label Content="{Binding text}"/>
</Button>
</StackPanel>
</Grid>
というときに Content は Binding のソースオブジェクトとして Label の DataContext プロパティを見ます<StackPanel>
<Button>
<Label Content="{Binding text}"/>
</Button>
</StackPanel>
</Grid>
Label に DataContext プロパティが設定されていない場合は DataContext に親要素の DataContext を設定します
親を辿っていくので 最終的に Window の DataContext が Window 内全部の要素の DataContext として使えるというわけです
上の XAML で適当に Window.DataContext を設定すれば Grid, StackPanel, Button, Label の DataContext を == でチェックするとすべて true で Window.DataContext の値になっています
Window とは違う Datacontext はButton に設定するとこうなります
<Grid x:Name="grid">
<StackPanel x:Name="stackpanel">
<Button x:Name="button">
<Label x:Name="label" Content="{Binding text}"/>
</Button>
</StackPanel>
</Grid>
<StackPanel x:Name="stackpanel">
<Button x:Name="button">
<Label x:Name="label" Content="{Binding text}"/>
</Button>
</StackPanel>
</Grid>
public MainWindow()
{
this.DataContext = new BindingData1();
this.button.DataContext = new BindingData2();
}
{
this.DataContext = new BindingData1();
this.button.DataContext = new BindingData2();
}
grid {samproj.MainWindow.BindingData1}
stackpanel {samproj.MainWindow.BindingData1}
button {samproj.MainWindow.BindingData2}
label {samproj.MainWindow.BindingData2}
stackpanel {samproj.MainWindow.BindingData1}
button {samproj.MainWindow.BindingData2}
label {samproj.MainWindow.BindingData2}
button の子要素になる label も button に設定された BindingData2 が DataContext です
button より親の要素は Window に設定された BindingData1 が DataContext です
UserControl
UserControl の場合<Grid>
<UserControl1 value="{Binding val"} />
</Grid>
<UserControl1 value="{Binding val"} />
</Grid>
のように Window の中に存在します
UserControl を作るときに UserControl の中で DataContext を設定していた場合は それが DataContext になっているので Window の DataContext ではなくなってしまいます
public UserControl1()
{
this.DataContext = new UserConrolDataContext();
}
{
this.DataContext = new UserConrolDataContext();
}
public MainWindow()
{
this.DataContext = new WindowDataContext();
}
{
this.DataContext = new WindowDataContext();
}
<Window 略>
<Grid>
<UserControl1 value="{Binding val"} />
<!-- ▲ WindowDataContext じゃなくて UserControlDataContext の val に Binding -->
</Grid>
</Window>
<Grid>
<UserControl1 value="{Binding val"} />
<!-- ▲ WindowDataContext じゃなくて UserControlDataContext の val に Binding -->
</Grid>
</Window>
WindowDataContext のつもりで value="{Binding val"} を書いていても DataContext は UserControlDataContext のものになっています
わかりづらくて バグのもとなので UserControl では DataContext をソースにする Binding を使わないか ルートになる Grid とか Stackpanel とかに名前をつけてそこに Binding するのが安全です
<UserControl 略>
<Grid x:Name="root_element">
<Label>a</Label>
</Grid>
</UserControl>
<Grid x:Name="root_element">
<Label>a</Label>
</Grid>
</UserControl>
public UserControl1()
{
this.root_element = new UserControlDataContext();
}
{
this.root_element = new UserControlDataContext();
}
こんな感じ