どうすればRelativeSourceでWPFバインディングを使用できますか?

2008年09月17日に質問されました。  ·  閲覧回数 442.9k回  ·  ソース

David Schmitt picture
2008年09月17日

WPFバインディングでRelativeSourceを使用するにはどうすればよいですか?また、さまざまなユースケースは何ですか?

回答

Abe Heidebrecht picture
2008年09月17日
800

オブジェクトの別のプロパティにバインドする場合:

{Binding Path=PathToProperty, RelativeSource={RelativeSource Self}}

祖先のプロパティを取得する場合:

{Binding Path=PathToProperty,
    RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}}

テンプレート化された親のプロパティを取得する場合(ControlTemplateで双方向バインディングを実行できるようにするため)

{Binding Path=PathToProperty, RelativeSource={RelativeSource TemplatedParent}}

または、より短い(これはOneWayバインディングでのみ機能します):

{TemplateBinding Path=PathToProperty}
Drew Noakes picture
2009年03月03日
133
Binding RelativeSource={
    RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemType}
}
...

RelativeSourceのデフォルト属性は、 Modeプロパティです。 有効な値の完全なセットはここにあります( MSDNから):

  • PreviousDataはあなたが表示されているデータ項目のリスト内の前のデータ項目(データ項目が含まれていない、そのコントロール)に結合することができます。

  • TemplatedParentテンプレート(データバインドされた要素が存在する)が適用される要素を参照します。 これは、TemplateBindingExtensionの設定に似ており、バインディングがテンプレート内にある場合にのみ適用できます。

  • 自己バインディングを設定している要素を参照し、その要素の1つのプロパティを同じ要素の別のプロパティにバインドできるようにします。

  • FindAncestorデータバインドされた要素の親チェーン内の祖先を参照します。 これを使用して、特定のタイプまたはそのサブクラスの祖先にバインドできます。 これは、AncestorTypeやAncestorLevelを指定する場合に使用するモードです。

Jeffrey Knight picture
2011年03月16日
128

MVVMアーキテクチャのコンテキストでのより視覚的な説明は次のとおりです。

enter image description here

Cornel Marian picture
2013年10月20日
48

Bechir Bejaouiは、WPFのRelativeSourcesのユースケースを彼の記事で公開しています。

相対ソースは、特定のオブジェクトのプロパティをオブジェクト自体の別のプロパティにバインドしようとするとき、オブジェクトのプロパティをその相対的な親の別のプロパティにバインドしようとするときに、特定のバインドの場合に使用されるマークアップ拡張です。カスタムコントロール開発の場合、および最後に一連のバインドされたデータの差分を使用する場合に、依存関係プロパティ値をXAMLの一部にバインドするとき。 これらの状況はすべて、相対ソースモードとして表されます。 これらすべてのケースを1つずつ公開します。

  1. モードセルフ:

この場合、高さが常に幅と等しくなるようにしたい長方形、たとえば正方形を想像してみてください。 要素名を使用してこれを行うことができます

<Rectangle Fill="Red" Name="rectangle" 
                Height="100" Stroke="Black" 
                Canvas.Top="100" Canvas.Left="100"
                Width="{Binding ElementName=rectangle,
                Path=Height}"/>

ただし、上記の場合、バインディングオブジェクトの名前、つまり長方形を指定する必要があります。 相対ソースを使用して、同じ目的を異なる方法で達成できます

<Rectangle Fill="Red" Height="100" 
               Stroke="Black" 
               Width="{Binding RelativeSource={RelativeSource Self},
               Path=Height}"/>

その場合、バインディングオブジェクトの名前を指定する義務はなく、高さが変更されるたびに幅は常に高さに等しくなります。

幅を高さの半分にパラメーター化する場合は、バインディングマークアップ拡張機能にコンバーターを追加することでこれを行うことができます。 今、別のケースを想像してみましょう:

 <TextBlock Width="{Binding RelativeSource={RelativeSource Self},
               Path=Parent.ActualWidth}"/>

上記のケースは、特定の要素の特定のプロパティをその直接の親のプロパティの1つに関連付けるために使用されます。これは、この要素が親と呼ばれるプロパティを保持しているためです。 これにより、FindAncestorモードである別の相対ソースモードにつながります。

  1. モードFindAncestor

この場合、特定の要素のプロパティは、その親の1つであるOfCorseに関連付けられます。 上記の場合との主な違いは、プロパティを関連付けるために、階層内の祖先タイプと祖先ランクを決定するのはあなた次第であるという事実です。 ちなみに、この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要素と、階層的な親を表すキャンバス要素です。 2番目のTextBlockは、相対ソースレベルで指定された親の名前を表示します。

したがって、AncestorLevel = 2をAncestorLevel = 1に変更して、何が起こるかを確認してください。 次に、祖先のタイプをAncestorType = BorderからAncestorType = Canvasに変更して、何が起こるかを確認します。

表示されるテキストは、祖先のタイプとレベルに応じて変化します。 次に、祖先レベルが祖先タイプに適していない場合はどうなりますか? これは良い質問です、私はあなたがそれを尋ねようとしていることを知っています。 応答は例外ではなく、TextBlockレベルでは何も表示されません。

  1. TemplatedParent

このモードでは、特定の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とは対照的に、コンパイル時に評価されます。 次の図でわかるように、背景とコンテンツはボタン内からコントロールテンプレートに適用されます。

Kylo Ren picture
2016年01月21日
34

WPFでは、 RelativeSourceバインディングにより、3つのpropertiesが公開されます。

1.モード:これはenumであり、次の4つの値を持つことができます。

a。 propertyの以前の値をバインドされた値に割り当てます

b。 templates任意のコントロールのをとの値/プロパティにバインドするcontrol

たとえば、 ControlTemplate定義します。

  <ControlTemplate>
        <CheckBox IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
 </ControlTemplate>

c。 selfまたはpropertyのselfからバインドする場合。

たとえば:センドがの状態確認checkboxとしてCommandParameterに設定しながら、 CommandCheckBox

<CheckBox ...... CommandParameter="{Binding RelativeSource={RelativeSource Self},Path=IsChecked}" />

d。 Visual Treecontrolからバインドする場合。

例: grid場合、 header checkboxがチェックされている場合、 checkboxrecordsバインドします

<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場合、どのレベルの祖先( visual tree同じタイプの親が2つある場合)

RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type iDP:XamDataGrid, AncestorLevel=1}}

上記はすべてRelativeSource bindingユースケースです。

ここに参照リンクがあります。

Bob King picture
2008年09月17日
21

TemplatedParentを忘れないでください:

<Binding RelativeSource="{RelativeSource TemplatedParent}"/>

または

{Binding RelativeSource={RelativeSource TemplatedParent}}
Matthew Black picture
2010年04月25日
15

このSilverlightの考え方に出くわした人にとっては、注目に値します。

Silverlightは、これらのコマンドのサブセットのみを提供します

Luis Perez picture
2012年08月07日
15

私は、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

メソッドのバインドに使用する「BEFORE」の例では、最後にチェックしたRelayCommandを使用してコードが既に最適化されており、WPFのネイティブ部分ではないことに注意してください。 それがなければ、「BEFORE」の例はさらに長くなります。

Nathan Cooper picture
2012年10月30日
15

いくつかの便利な断片:

主にコードでそれを行う方法は次のとおりです。

Binding b = new Binding();
b.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, this.GetType(), 1);
b.Path = new PropertyPath("MyElementThatNeedsBinding");
MyLabel.SetBinding(ContentProperty, b);

私はこれをBindingRelativeSourceから

また、MSDNページは例としてはかなり良いです: RelativeSourceクラス

Juve picture
2010年08月23日
11

Silverlightの親要素のDataContextにアクセスするための別のソリューションを投稿しました。 Binding ElementNameます。