web-dev-qa-db-ja.com

ToolTipまたはContextMenuからのRelativeSourceバインディング

私はここで何が間違っているのですか?:

 <GridViewColumn>
    <GridViewColumn.CellTemplate>
       <DataTemplate>
          <Button>
            <Button.ToolTip>
              <TextBlock Text="{Binding Path=Title, RelativeSource={RelativeSource AncestorType=Window}}" />

これは単純化された例であり、とにかく機能しません:)実際には、ウィンドウのDataContextのスコープ内にある別のプロパティから値を取得する必要があります。

私を助けてください。

30
iLemming

ToolTipはVisualTreeの一部ではないため、これは注意が必要です。 ここ ContextMenusの同じ問題に対するクールな解決策があります。ツールチップを使用するのと同じ方法です。

[〜#〜]更新[〜#〜]
残念ながらリンクがなくなり、参照されている記事が見つかりませんでした。
私が覚えている限り、参照されているブログは、別のVisualTreeのDataContextにバインドする方法を示しています。これは、ToolTip、ContextMenu、またはPopupからバインドするときに必要になることがよくあります。

これを行う良い方法は、PlacementTargetのTagプロパティ内に目的のインスタンス(ViewModelなど)を提供することです。次の例は、ViewModelのコマンドインスタンスにアクセスするためにこれを行います。

<Button Tag="{Binding DataContext,RelativeSource={RelativeSource Mode=Self}}">
  <Button.ContextMenu>
    <ContextMenu>
       <MenuItem Command="{Binding PlacementTarget.Tag.DesiredCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" .../>
    <ContextMenu>
  </Button.ContextMenu>
</Button>

私はそれをテストしていません、そしてそれは私が最後にこれをした長い間です。うまくいかない場合はコメントしてください。

UPDATE 2

この回答が書かれた元のリンクがなくなったので、archive.orgにアクセスして 元のブログエントリを見つけました 。これが、ブログから逐語的にです:

WPFのContextMenuは、ページ/ウィンドウ/コントロール自体のビジュアルツリー内に存在しないため、データバインディングは少し注意が必要です。私はこれをウェブ全体で高低で検索しましたが、最も一般的な答えは「コードビハインドでそれを行うだけ」のようです。違う! XAMLのすばらしい世界に戻って、コードビハインドでの作業に戻ることはありませんでした。

これが私の例です。これにより、ウィンドウのプロパティとして存在する文字列にバインドできます。

public partial class Window1 : Window
{
    public Window1()
    {
        MyString = "Here is my string";
    }

    public string MyString
    {
        get;
        set;

    }
}


<Button Content="Test Button" 
     Tag="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
  <Button.ContextMenu>
    <ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, 
          RelativeSource={RelativeSource Self}}" >
      <MenuItem Header="{Binding MyString}"/>
    </ContextMenu>
  </Button.ContextMenu>   
</Button>

重要な部分はボタンのタグです(ボタンのDataContextを同じように簡単に設定できますが)。これにより、親ウィンドウへの参照が保存されます。 ContextMenuは、PlacementTargetプロパティを介してこれにアクセスできます。次に、このコンテキストをメニュー項目に渡すことができます。

これは世界で最もエレガントなソリューションではないことを認めます。ただし、コードビハインドの設定に勝るものはありません。誰かがこれを行うためのさらに良い方法を持っているなら、私はそれを聞いてみたいです。

69
HCL

以下のとおり:
PlacementTargetは、ContextMenuを所有するコントロールです(例:DataGrid)。 「タグ」プロパティは必要ありません。

IsEnabledは、DataGridの「myProperty」値にバインドします。

私はこれをテストしました、そしてそれは働きます。バインディングに関して同様の問題がありました。

<ContextMenu
DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource Self}}"
IsEnabled="{Binding myProperty}"  
>
3
rr789

ContextMenuはビジュアルツリーにないため、バインディングは機能しません。簡単な解決策はプロキシパターンを使用することです。DependencyObjectから継承し、DependencyPropertyDataContextを保持するWindowを持つラッパークラスを作成できます。 、次に、XAMLにプロキシのリソースを設定し、最後にプロキシオブジェクトを介してMenuItemコマンドを目的のコマンドにバインドできます。
サンプルプロキシ:

Public class ProxyClass : DependencyObject
{
    Public object Data {get; set;}
   public static readonly DependencyProperty DataProperty = DependencyProperty.Register("DataProperty", typeof(object), typeof(ProxyClass), new FrameworkPropertyMetadata(null));

}

XAMLでの使用方法:

<Window DataContext="{Binding MyViewModel}">
...
<Window.Resources>
    <ProxyClass Data={Binding} x:Key="BindingProxy"/>

</Window.Resources>
...  
<MenuItem Command="{Binding Source={StaticResource BindingProxy}, Path=Data.MyDesiredCommand"/>
...
</Window>

何が起こっているのですか?
DataProxyClassのプロパティはDataContextWindowにバインドされ、ViewModelのすべてのコマンドとプロパティが含まれます。 var] _ ProxyClassリソース内。
このアプローチのもう1つの利点は、移植性と複数のビューやプロジェクトでの再利用です。

0
Amir Oveisi