MyTextBox
から継承するカスタム コントロール を作成しましたTextBox
。名前付きコントロールを含むスタイルが関連付けられています。
<Style x:Key="{x:Type MyTextBox}" TargetType="{x:Type MyTextBox}">
<!-- ... -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type MyTextBox}">
<!-- ... -->
<SomeControl x:Name="PART_SomeControl" />
<!-- ... -->
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
MyTextBox
には依存関係プロパティがあり、設定すると、その値が次のように伝播されますSomeControl
。
public class MyTextBox : TextBox
{
// ...
public static new readonly DependencyProperty MyParameterProperty =
DependencyProperty.Register(
"MyParameter",
typeof(object),
typeof(MyTextBox),
new PropertyMetadata(default(object), MyParameterChanged));
private static void MyParameterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var me = (MyTextBox)d;
var someControl = (SomeControl)me.GetTemplateChild("PART_SomeControl");
someControl.SetValue(SomeControl.MyParameterProperty, e.NewValue);
}
}
これは、次のように単純なバインディングを行う場合にうまく機能します。
<MyTextBox MyParameter="{Binding}" />
しかし、次のように、RelativeSource を使用してより高度なバインディングを使用すると、次のようになります。
<MyTextBox MyParameter="{Binding DataContext, RelativeSource={RelativeSource
FindAncestor, AncestorType=ParentView}}"
メソッドは をme.GetTemplateChild()
返しますnull
。つまり、SomeControl
見つからない。
なんで?
私が行った観察の 1 つは、 がある場合RelativeSource
、MyParameter
依存関係プロパティがすべての依存関係プロパティの最初に設定されるということです。つまり、次のようなことをすると:
<MyTextBox
OtherParameter="{Binding}"
MyParameter="{Binding DataContext, RelativeSource={RelativeSource
FindAncestor, AncestorType=ParentView}}"
MyParameter
プロパティは (奇妙なことに) の前に設定されていOtherParameter
ます。単純なバインディングを使用すると、予想どおり、宣言されたのと同じ順序で設定されます。
(ご覧のとおり、私のコードは無関係なものから取り除かれています。うまくいけば、重要なものはすべて含まれています。)