web-dev-qa-db-ja.com

親DataContextへのWPFバインディング

View-> ViewModelの解像度にCinch(したがってMefedMVVM)を利用する、標準のMVVMパターンを持つWPFアプリケーションがあります。これはうまく機能し、関連するコントロールをViewModelのプロパティにバインドできます。

特定のビュー内には、Infragistics XamGridがあります。このグリッドは、ViewModelのObservableCollectionにバインドされ、適切な行を表示します。ただし、このグリッドには特定の列があり、ObservableCollectionではなく、親のDataContextのプロパティにTextBoxテキスト値をバインドしようとしています。このバインディングは失敗しています。

以下を含むいくつかのオプションがあります。

  1. AncestorTypeを使用してツリーを追跡し、親UserControlのDataContextにバインドします( great answer からこの質問へ、および this one )...

    {Binding Path=PathToProperty, RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}}
    
  2. ElementNameを指定し、トップレベルコントロールを直接ターゲットにしようとしています。 ElementNameの使用について読みたい場合は、 こちらをご覧ください を用意してください。

  3. UserControlのリソースで定義された「プロキシ」FrameorkElementを使用して、必要に応じてコンテキストを「通過」させます。以下のように要素を定義してから、静的リソースとして参照します...

    <FrameworkElement x:Key="ProxyContext" DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource Self}}"></FrameworkElement>
    

この場合、バインディングはFrameworkElementを検出しますが、それを超えるものにはアクセスできません(パスを指定する場合)。

読み返してみると、これはInfragistics XamGridがツリーの外側に列を構築していることが原因である可能性が高いようです。ただし、この場合でも、少なくともオプション2または3は機能するはずです。

私たちの最後の考えは、それがV-VMバインディングに関連しているということですが、Snoopを使用しても、正確な問題が何であるかはまだわかりません。ポインターを高く評価するためにバインドします。

編集:Infragistics here のテンプレート例をいくつか見つけました。

編集2:@Dtexによって指摘されているように、テンプレートは進むべき道です。 XamGridで使用する関連スニペットは次のとおりです。

<ig:GroupColumn Key="CurrentDate">
                <ig:GroupColumn.HeaderTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Path=DataContext.CurrentDateTest, RelativeSource={RelativeSource AncestorType=UserControl}}" />
                    </DataTemplate>
                </ig:GroupColumn.HeaderTemplate>
                <ig:GroupColumn.Columns>

XMLを開いたままにしておきます。必要な列を追加し、関連するタグを閉じます。

44
Nick

私はXamGridについて知りませんが、それは標準のwpf DataGridで何をするかです:

<DataGrid>
    <DataGrid.Columns>
        <DataGridTemplateColumn>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding DataContext.MyProperty, RelativeSource={RelativeSource AncestorType=MyUserControl}}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
            <DataGridTemplateColumn.CellEditingTemplate>
                <DataTemplate>
                    <TextBox Text="{Binding DataContext.MyProperty, RelativeSource={RelativeSource AncestorType=MyUserControl}}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellEditingTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

セルテンプレートで指定されたTextBlockTextBoxはビジュアルツリーの一部になるため、必要なコントロールを見つけて見つけることができます。

81
Dtex

このようなことから、一般的な経験則として、XAMLの「トリッキー」をできるだけ避け、XAMLをできるだけ愚かでシンプルに保ち、残りをViewModel(または添付プロパティまたはIValueConvertersなど)で処理するようにしています。本当に必要な場合)。

可能であれば、現在のDataContextのViewModelに関連する親ViewModelへの参照(つまりプロパティ)を与えます

public class ThisViewModel : ViewModelBase
{
    TypeOfAncestorViewModel Parent { get; set; }
}

代わりに直接それに対してバインドします。

<TextBox Text="{Binding Parent}" />

0
bitbonk