RelativeSource
WPFバインディングでどのように使用しますか?また、さまざまなユースケースは何ですか?
14 に答える
オブジェクトの別のプロパティにバインドする場合:
{Binding Path=PathToProperty, RelativeSource={RelativeSource Self}}
祖先のプロパティを取得する場合:
{Binding Path=PathToProperty,
RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}}
テンプレート化された親のプロパティを取得する場合 (そのため、ControlTemplate で 2 ウェイ バインディングを実行できます)
{Binding Path=PathToProperty, RelativeSource={RelativeSource TemplatedParent}}
または、より短い (これは OneWay バインディングでのみ機能します):
{TemplateBinding Path=PathToProperty}
Binding RelativeSource={
RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemType}
}
...
のデフォルト属性RelativeSource
はMode
プロパティです。有効な値の完全なセットはここにあります(MSDNから):
PreviousData表示されているデータ項目のリストで、前のデータ項目(データ項目を含むコントロールではない)をバインドできます。
TemplatedParentテンプレート(データバインドされた要素が存在する)が適用される要素を参照します。これは、TemplateBindingExtensionの設定に似ており、Bindingがテンプレート内にある場合にのみ適用できます。
自己バインディングを設定している要素を参照し、その要素の1つのプロパティを同じ要素の別のプロパティにバインドできるようにします。
FindAncestorデータバインドされた要素の親チェーン内の祖先を参照します。これを使用して、特定のタイプまたはそのサブクラスの祖先にバインドできます。これは、AncestorTypeやAncestorLevelを指定する場合に使用するモードです。
MVVM アーキテクチャのコンテキストでのより視覚的な説明を次に示します。
Bechir Bejaoui は、こちらの記事で WPF の RelativeSources のユース ケースを公開しています。
RelativeSource は、特定のオブジェクトのプロパティをオブジェクト自体の別のプロパティにバインドしようとするとき、オブジェクトのプロパティをその相対的な親の別のプロパティにバインドしようとするときに、特定のバインディング ケースで使用されるマークアップ拡張機能です。カスタム コントロール開発の場合に依存関係プロパティ値を XAML の一部にバインドするとき、および最後に一連のバインドされたデータの差分を使用する場合。これらの状況はすべて、相対的なソース モードとして表現されます。それらのすべてのケースを1つずつ公開します。
- モードセルフ:
このケースを想像してみてください。高さが常に幅と等しい長方形、たとえば正方形を考えてみましょう。要素名を使用してこれを行うことができます
<Rectangle Fill="Red" Name="rectangle" Height="100" Stroke="Black" Canvas.Top="100" Canvas.Left="100" Width="{Binding ElementName=rectangle, Path=Height}"/>
しかし、上記の場合、バインディング オブジェクトの名前、つまり四角形を指定する必要があります。RelativeSource を使用して、同じ目的を異なる方法で達成できます
<Rectangle Fill="Red" Height="100" Stroke="Black" Width="{Binding RelativeSource={RelativeSource Self}, Path=Height}"/>
その場合、バインディング オブジェクトの名前を言及する義務はありません。高さが変更されるたびに、Width は常に Height と等しくなります。
幅を高さの半分にパラメーター化する場合は、Binding マークアップ拡張機能にコンバーターを追加することでこれを行うことができます。別のケースを想像してみましょう:
<TextBlock Width="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualWidth}"/>
上記のケースは、この要素が Parent と呼ばれるプロパティを保持しているため、特定の要素の特定のプロパティをその直接の親のプロパティの 1 つに結び付けるために使用されます。これは、FindAncestor である別の相対ソース モードにつながります。
- モード FindAncestor
この場合、特定の要素のプロパティは、その親の 1 つである Of Corse に関連付けられます。上記のケースとの主な違いは、プロパティを関連付けるために、階層内の祖先のタイプと祖先のランクを決定するのはユーザー次第であるという事実です。ところで、この XAML で遊んでみてください
<Canvas Name="Parent0"> <Border Name="Parent1" Width="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualWidth}" Height="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualHeight}"> <Canvas Name="Parent2"> <Border Name="Parent3" Width="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualWidth}" Height="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualHeight}"> <Canvas Name="Parent4"> <TextBlock FontSize="16" Margin="5" Text="Display the name of the ancestor"/> <TextBlock FontSize="16" Margin="50" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Border}, AncestorLevel=2},Path=Name}" Width="200"/> </Canvas> </Border> </Canvas> </Border> </Canvas>
上記の状況は、一連の境界内に埋め込まれた 2 つの TextBlock 要素と、それらの階層的な親を表す canvas 要素の場合です。2 番目の TextBlock は、指定された親の名前を相対的なソース レベルで表示します。
そのため、AncestorLevel=2 を AncestorLevel=1 に変更して、何が起こるかを確認してください。次に、祖先のタイプを AncestorType=Border から AncestorType=Canvas に変更して、何が起こるかを確認してください。
先祖の種類やレベルによって表示される文字が変わります。では、祖先レベルが祖先タイプに適していない場合はどうなるでしょうか? これは良い質問です。あなたが尋ねようとしていることは知っています。例外はスローされず、TextBlock レベルでは何も表示されません。
- テンプレート化された親
このモードでは、特定の ControlTemplate プロパティを、ControlTemplate が適用されるコントロールのプロパティに関連付けることができます。ここで問題をよく理解するために、以下の例を示します
<Window.Resources> <ControlTemplate x:Key="template"> <Canvas> <Canvas.RenderTransform> <RotateTransform Angle="20"/> </Canvas.RenderTransform> <Ellipse Height="100" Width="150" Fill="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background}"> </Ellipse> <ContentPresenter Margin="35" Content="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Content}"/> </Canvas> </ControlTemplate> </Window.Resources> <Canvas Name="Parent0"> <Button Margin="50" Template="{StaticResource template}" Height="0" Canvas.Left="0" Canvas.Top="0" Width="0"> <TextBlock FontSize="22">Click me</TextBlock> </Button> </Canvas>
特定のコントロールのプロパティをそのコントロール テンプレートに適用する場合は、TemplatedParent モードを使用できます。このマークアップ拡張機能に似たものもあり、これは最初のものの省略形の一種である TemplateBinding ですが、TemplateBinding はコンパイル時に評価され、最初の実行直後に評価される TemplatedParent とは対照的です。次の図でわかるように、背景とコンテンツはボタン内からコントロール テンプレートに適用されます。
WPFRelativeSource
バインディングでは、次の 3 つproperties
の設定を公開します。
1. モード:これは、次のenum
4 つの値を持つことができる です。
を。PreviousData(
value=0
):property
の以前の値をバインドされたものに割り当てますb. TemplatedParent(
value=1
): これは、任意のコントロールの を定義templates
し、 の値/プロパティにバインドするcontrol
ます。たとえば、次のように定義します
ControlTemplate
。
<ControlTemplate>
<CheckBox IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</ControlTemplate>
c. Self(
value=2
):self
自分の aまたは aからバインドしたい場合property
。例: onを設定しながら、
checkbox
asのチェック状態を送信します。CommandParameter
Command
CheckBox
<CheckBox ...... CommandParameter="{Binding RelativeSource={RelativeSource Self},Path=IsChecked}" />
d. FindAncestor(
value=3
):で親からバインドしたいcontrol
場合Visual Tree
。例: if a ,ifがチェック
checkbox
されている場合に a をバインドします。records
grid
header
checkbox
<CheckBox IsChecked="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type iDP:XamDataGrid}}, Path=DataContext.IsHeaderChecked, Mode=TwoWay}" />
2. AncestorType: モードがFindAncestor
どのタイプの祖先かを定義する場合
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type iDP:XamDataGrid}}
3. AncestorLevel: モードがFindAncestor
祖先のレベルの場合 (同じタイプの親が 2 つある場合visual tree
)
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type iDP:XamDataGrid, AncestorLevel=1}}
上記は のすべての使用例です
RelativeSource binding
。
ここに参照リンクがあります。
TemplatedParent を忘れないでください:
<Binding RelativeSource="{RelativeSource TemplatedParent}"/>
また
{Binding RelativeSource={RelativeSource TemplatedParent}}
RelativeSource を使いやすくするなど、WPF のバインド構文を簡素化するライブラリを作成しました。下記は用例です。前:
{Binding Path=PathToProperty, RelativeSource={RelativeSource Self}}
{Binding Path=PathToProperty, RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}}
{Binding Path=PathToProperty, RelativeSource={RelativeSource TemplatedParent}}
{Binding Path=Text, ElementName=MyTextBox}
後:
{BindTo PathToProperty}
{BindTo Ancestor.typeOfAncestor.PathToProperty}
{BindTo Template.PathToProperty}
{BindTo #MyTextBox.Text}
メソッドバインディングがどのように単純化されるかの例を次に示します。前:
// C# code
private ICommand _saveCommand;
public ICommand SaveCommand {
get {
if (_saveCommand == null) {
_saveCommand = new RelayCommand(x => this.SaveObject());
}
return _saveCommand;
}
}
private void SaveObject() {
// do something
}
// XAML
{Binding Path=SaveCommand}
後:
// C# code
private void SaveObject() {
// do something
}
// XAML
{BindTo SaveObject()}
ここでライブラリを見つけることができます: http://www.simplygoodcode.com/2012/08/simpler-wpf-binding.html
メソッドバインディングに使用する「BEFORE」の例では、RelayCommand
最後にチェックしたものを使用してコードが既に最適化されていることに注意してください。これは WPF のネイティブ部分ではありません。それがなければ、「BEFORE」の例はさらに長くなっていたでしょう。
この Silverlight の考え方に出くわした人にとっては、次の点に注意してください。
Silverlight は、これらのコマンドの縮小されたサブセットのみを提供します
いくつかの便利な小片:
主にコードでそれを行う方法は次のとおりです。
Binding b = new Binding();
b.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, this.GetType(), 1);
b.Path = new PropertyPath("MyElementThatNeedsBinding");
MyLabel.SetBinding(ContentProperty, b);
コード ビハインドの Binding Relative Sourceからこれを大部分コピーしました。
また、例に関する限り、MSDN ページは非常に優れています: RelativeSource クラス
Silverlight の親要素の DataContext にアクセスするための別のソリューションを投稿しました。を使用していますBinding ElementName
。
これは、空のデータグリッドで機能したこのパターンの使用例です。
<Style.Triggers>
<DataTrigger Binding="{Binding Items.Count, RelativeSource={RelativeSource Self}}" Value="0">
<Setter Property="Background">
<Setter.Value>
<VisualBrush Stretch="None">
<VisualBrush.Visual>
<TextBlock Text="We did't find any matching records for your search..." FontSize="16" FontWeight="SemiBold" Foreground="LightCoral"/>
</VisualBrush.Visual>
</VisualBrush>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>