web-dev-qa-db-ja.com

UserControlのDataContext

私はこのようなものを使用したいUserControlを作成しています:

<controls:ColorWithText Color="Red" Text="Red color" />

これまでのところ、次のような同様のコントロールを実装しました。

<UserControl x:Class="Namespace.ColorWithText" Name="ThisControl">
    <StackPanel Orientation="Horizontal" >
        <Border Width="15" Height="15" Background="{Binding Color, ElementName=ThisControl}" />
        <TextBlock Text="{Binding Text, ElementName=ThisControl}" />
    </StackPanel>
</UserControl>

ColorおよびTextは、コードで定義されたコントロールの依存関係プロパティです。これは機能しますが、毎回ElementNameを指定する必要はありません。

動作する別のオプションは

<UserControl x:Class=… DataContext="{Binding ElementName=ThisControl}" Name="ThisControl">

ElementNamesを指定していませんが、それも私にとってはきれいな解決策ではないようです。

2つの質問があります。

  1. なぜ<UserControl DataContext="{RelativeSource Self}">仕事?
  2. このようなことをする最良の方法は何ですか?
40
svick

最初に、試してください:

<UserControl DataContext="{Binding RelativeSource={RelativeSource Self}}">

2番目の質問では、ElementNameまたはAncestorBindingを使用することが、UserControlのプロパティにバインドする最適な方法だと思います。

59
decyclone

使用できない理由<UserControl DataContext="{RelativeSource Self}">

これは、コントロールを使用する方法です

<Grid DataContext="{StaticResource ViewModel}">
    <!-- Here we'd expect this control to be bound to -->
    <!-- ColorToUse on our ViewModel resource          -->
    <controls:ColorWithText Color="{Binding ColorToUse}" />
</Grid>

コントロールでデータコンテキストをハードコーディングしているため、ViewModelではなく、ColorWithTextオブジェクトでColorToUseプロパティをルックアップしようとします。失敗します。

これが、ユーザーコントロールでDataContextを設定できない理由です。 Brandur に感謝します。

このようなことをする最良の方法は何ですか?

代わりに、コントロールの最初の子UI要素でDataContextを設定する必要があります。

あなたの場合はあなたが欲しい

<StackPanel 
  DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"
  Orientation="Horizontal" >

コントロールを参照するDataContextができたので、相対バインディングを使用してそのコントロールのプロパティにアクセスできます。

19
pdross

あなたが使用する必要があります

{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=Color}

データバインディングに関連する疑問については、常にこのシートを参照してください。
http://www.nbdtech.com/Blog/archive/2009/02/02/wpf-xaml-data-binding-cheat-sheet.aspx

13
Prince Ashitaka

私はこれが回答されたことを知っていますが、どの説明もDataContextとその仕組みの理解を与えません。このリンクはそのために素晴らしい仕事をします。

WPF、SILVERLIGHT、およびWP7(パート2)でのデータバインドについて知りたいすべてのこと

あなたの質問#1に答えて

なぜ<UserControl DataContext="{RelativeSource Self}">仕事?

これは上記のリンクの要約です。 DataContextは、UserControl ElementレベルでSelfに設定しないでください。これは、DataContextの継承を破壊するためです。 selfに設定し、このコントロールをWindowまたは別のコントロールに配置すると、Windows DataContextを継承しません。

DataContextは、どこかで上書きされない限り、XAMLのすべての下位要素とUserControlのすべてのXAMLに継承されます。 UserControl DataContextをそれ自体に設定すると、DataContextが上書きされ、継承が中断されます。代わりに、XAMLの1つの要素、場合によってはStackPanelにネストします。ここにDataContextバインディングを配置し、UserControlにバインドします。これにより、継承が保持されます。

この詳細な説明については、以下のリンクも参照してください。

WPF/SILVERLIGHTで再利用可能なユーザーコントロールを作成するための簡単なパターン

あなたの質問#2に答えて
このようなことをする最良の方法は何ですか?

以下のコード例を参照してください。

<UserControl x:Class="Namespace.ColorWithText" Name="ThisControl">
    <StackPanel Orientation="Horizontal" DataContext={Binding ElementName=ThisControl}>
    <Border Width="15" Height="15" Background="{Binding Color" />
    <TextBlock Text="{Binding Text}" />
</StackPanel>

これを行うと、各バインディングでElementNameが不要になることに注意してください。

12
jdawiz

コンストラクタ自体でdatacontextをselfに設定できます。

public ColorWithText()
{
 InitializeComponent();
 DataContext = this;
}

今、あなたは単に言うことができます

<UserControl x:Class="Namespace.ColorWithText" Name="ThisControl">
    <StackPanel Orientation="Horizontal" >
        <Border Width="15" Height="15" Background="{Binding Color}" />
        <TextBlock Text="{Binding Text}" />
    </StackPanel>
</UserControl>
10
biju