2009-03-25 5 views
20

私は、UserControlで複数のdatacontextにホストされているコントロールにデータをバインドする方法を実際にはわからないシナリオがあります。複数のコントロールを異なるデータコンテキストにバインドするWPF

私はバインドするデータは、ユーザーコントロールのDataContextのは、私は簡単しかし、私ドン以下

<Label Name="LblEmail" Text="{Binding Email}" /> 

をやっほとんどのコントロールをバインドすることができたUserInfoに設定されている2クラス

UserInfo, UserExtendedInfo 

から来ていますUserExtendedInfoクラスからプロパティを簡単にバインドする方法を知っています。私の最初の考えは、UserExtendedInfoからのデータを使用する各コントロールのdatacontextを設定して、同じことができるようにすることでした。しかし、私は手動で個々に割り当てる必要があるので、これは面倒なようです。 UserExtendedInfoのデータは、UserControlが表示されるたびにデータベースからフェッチして、同期が外れないようにする必要があります。

XAML:背後に

<Label Name="LblTest" Text="{Binding Locale}" /> 

コード:

Private Sub UserManager_IsVisibleChanged(ByVal sender As System.Object, ByVal e As System.Windows.DependencyPropertyChangedEventArgs) 
     If DirectCast(e.NewValue, Boolean) Then 
      Dim user As UserInfo = DirectCast(DataContext, UserInfo) 

      If user IsNot Nothing Then 
       Dim usrExt As UserExtenedInfo = UserController.GetUserExtended(user.userID) 

       LblTest.DataContext = usrExt 
      Else 
       Throw New ArgumentException("UserId doesn't exist or is less than 1") 
      End If 
     End If 
    End Sub 

答えて

25

私は多分、データが含まれているサブパネルのDataContextのプロパティを設定する別々のクラスで、ユーザーオブジェクトをラップについて思うだろう。例えば

:中続い

public class UserDataContext 
{ 
    public UserInfo UserInfo { get; set; } 
    public UserExtendedInfo UserExtendedInfo { get; set; } 
} 

あなたUserControl.xaml

<!-- Binding for the UserControl should be set in its parent, but for clarity --> 
<UserControl DataContext="{Binding UserDataContext}"> 
    <StackPanel> 
    <Grid DataContext="{Binding UserInfo}"> 
     <TextBlock Text="{Binding Email}" /> 
    </Grid> 
    <Grid DataContext="{Binding UserExtendedInfo}"> 
     <TextBlock Text="{Binding Locale}" /> 
     <TextBlock Text="{Binding AboutMe}" /> 
    </Grid> 
    </StackPanel> 
</UserControl> 

これはあなたのUserInfoクラスは、電子メールの性質を持っていることを前提としてい

あなたのUserExtendedInfoクラスにはLocaleとAboutMeのプロパティ

+0

これは大変意味があります。 WPFで学ぶための新しいこと:) – Alex

+1

この特定のビューをサポートすることだけを目的とする新しいモデルを作成する代わりに、ビューにバインドできるViewModelのパブリックプロパティとしてUserInfoとUserExtendedInfoを追加してください。 (Richの[answer](http://stackoverflow.com/questions/679933/wpf-binding-multiple-controls-to-different-datacontexts/680052#680052)を参照してください)。 – totorocat

7

これは、M-V-VMが非常に便利な場所です。アイデアは(少なくとも私がそれを理解している限り...私にとってまだ新しくて)、ウィンドウ自体が "ViewModel"クラスにバインドされているということです。 ViewModelクラスは、ページ全体が必要とするすべてのものにアクセスできるようにすべてのデータを表すクラスです... 1つのクラスでバインドする必要のあるすべての異なるオブジェクトをまとめています。ウィンドウまたはページのDataContextをこのクラスのインスタンスに設定します。 UserInfoインスタンスとUserInfoExtendedインスタンスはViewModelオブジェクトのパブリックプロパティです。バインディング要素のPathを使用するだけで、各コントロールをバインドする適切なオブジェクトの適切なプロパティを取得できます。

このパターンを説明する大きなビデオがありますが、これを達成するためのさまざまな方法と、これがWPFアプリケーションで使用するための便利でスケーラブルなモデルであることを示す完全な例です。この例では、WPFの多くの機能と依存関係注入についても説明しています。

EDIT:削除されたブログの記事(この答えはかなり古いです)

はここで私が話してビデオへのリンクが含まれているブログ記事へのリンクです。ここではYouTubeの動画は、次のとおりです。

https://www.youtube.com/watch?v=BRxnZahCPFQ

+0

メモだけ、ViewModelは依存関係のプロパティを持つ必要はありません。コントロールのプロパティの1つに変更を反映させたい場合は、INotifyPropertyChangedを実装するだけです。 –

+0

リンクが死んでいます、あなたはリンクを更新しますか? –

+0

@HassanTareq YouTubeで見つけてリンクを更新しました – Rich

6

リッチとbendeweyどちらが良い答えを持っていました。 WPFの代わりにSilverlightでこの同じ話題を調べたところ、複数のDataContextを確立する必要はないことがわかりました。あなたがコントロールのコンテナのDataContextのを気にすることなく、異なるクラスのプロパティに混在する柔軟性と一致バインディングを得るバインディングパスを使用し

<UserControl DataContext="{Binding UserDataContext}"> 
    <StackPanel> 
     <TextBlock Text="{Binding Path=UserInfo.Email}" /> 
     <TextBlock Text="{Binding Path=UserExtendedInfo.Locale}" /> 
     <TextBlock Text="{Binding Path=UserExtendedInfo.AboutMe}" /> 
    </StackPanel> 
</UserControl> 

:bendeweyの例を改訂。

また、UserInfoクラスとUserExtendedInfoクラスのプロパティを操作するプロパティを追加することで、BendeweyのUserDataContextクラスの機能を拡張することもできます。たとえば、姓と名を組み合わせることができます。

INotifyPropertyChangedを実装して、UserInfoとUserExtendedInfoをリセットしたときにコントロールが更新されるようにすることができます。

基本的なUserInfoクラスとUserExtendedInfoクラスをXAMLから完全に分離するには、必要なプロパティをUserDataContextに直接公開し、Binding Pathの必要性を排除することがアーキテクチャ上望ましい場合があります。

+1

これはベンドウェイの答え(+1)の改善ですが、私はもう少し改善するでしょう: "Path ="は必要なく、ケースの95%明示的なクラスの代わりにC#の匿名型を使用します。 –

15

これはすべての中で最も簡単な方法です。非常にうまく動作します。コードビハインドあなたはコンテキストを設定するには

、単純にすべての必要な値を含む匿名型を使用します。あなたが何かに結合することができ、XAMLで

DataContext = new 
{ 
    info = FetchUserInfoFromDatabase(), 
    extendedInfo = FetchExtendedUserInfoFromDatabase(), 
}; 

を:

また
<UserControl> 
    <StackPanel> 
    <TextBlock Text="{Binding info.Email}" /> 
    <TextBlock Text="{Binding extendedInfo.Locale} /> 
    ... 

他の回答が記述しているように、2つのレベルでバインドすることができます。

<UserControl> 
    <StackPanel> 
    <Grid DataContext="{Binding info}"> 
     <TextBlock Text={Binding Email}"> 
     ... 
+0

ありがとう!私はトンを助けた! –

関連する問題