ツールチップまたはコンテキストメニューからのバインディングのbinding
-
01-10-2019 - |
質問
ここで何が間違っているのですか?:
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button>
<Button.ToolTip>
<TextBlock Text="{Binding Path=Title, RelativeSource={RelativeSource AncestorType=Window}}" />
これは単純化された例であり、とにかくうまくいきません:)実際に、ウィンドウのDataContextの範囲にある別のプロパティから値を取得する必要があります。
私を助けてくださいpls。
解決
ツールチップはビジュアルツリーの一部ではないため、これは難しいです。 ここ コンテキストマナスと同じ問題に対するクールな解決策があります。同じ方法でツールチップに行くことができます。
アップデート
悲しいことに、リンクはなくなりました、そして、私はもう参照された記事を見つけていません。
私が覚えている限り、参照されるブログは、別のビジュアルツリーのデータコンテキストにバインドする方法を示しています。
これを行う良い方法は、PlacementTargetのタグプロパティ内で目的のインスタンス(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>
私はそれをテストしていません、そして、それは私が前回これをした長い時間です。それがあなたのために機能しない場合はコメントをしてください。
更新2
この答えが書かれた元のリンクがなくなったので、私はarchive.orgを押して 元のブログエントリを見つけました. 。ここに、ブログからの逐語的:
WPFのコンテキストメニューは、ページ/ウィンドウ/コントロール自体の視覚ツリー内に存在しないため、データバインディングは少し難しい場合があります。私はこれをウェブ上で高くて低く検索しましたが、最も一般的な答えは「背後にあるコードでそれをするだけ」です。間違い!私は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>
重要な部分はボタンのタグです(ただし、ボタンのデータコンテキストを簡単に設定できます)。これにより、親のウィンドウへの参照が保存されます。 ContextMenuは、ITのPlacementTargetプロパティを介してこれにアクセスできます。その後、メニュー項目を介してこのコンテキストを渡すことができます。
これは世界で最もエレガントなソリューションではないことを認めます。ただし、背後にあるコードの設定に勝るものになります。誰かがこれを行うためのさらに良い方法を持っているなら、私はそれを聞いてみたいです。
他のヒント
以下のごとに:
PlacementTargetは、ContextMenuを所有するコントロールです(例:Datagrid)。 「タグ」プロパティは必要ありません。
IsEnabledは、Datagridの「MyProperty」値にバインドします。
これをテストしましたが、機能します。バインディングと同様の問題を抱えていました。
<ContextMenu
DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource Self}}"
IsEnabled="{Binding myProperty}"
>
なぜなら ContextMenu
ビジュアルツリーにないため、バインディングは機能しません。簡単なソリューションはプロキシパターンを使用することです。 DependencyObject
と DependencyProperty
それはaを維持します DataContext
あなたの 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>
何が起こっている?
Data
の財産 ProxyClass
にバインドします DataContext
の Window
, 、それからあなたのすべてのcomamndsとあなたのプロパティがあります ViewModel
内側 ProxyClass
資源。
このアプローチのもう1つの利点は、携帯性と複数のビューやプロジェクトで再利用されることです。
私はそれがこのように行われるべきだと思います:
{Binding Path=Title, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"