質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

XAML

XAML(Extensible Application Markup Language)はWPF、Silverlight、Windows PhoneそしてWindows Store appsでユーザーインターフェースを定義するために使われるXML言語です。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

解決済

2回答

4417閲覧

ContextMenuを挟むと、RelativeSourceを使ってBindすることができない

OZONE

総合スコア9

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

XAML

XAML(Extensible Application Markup Language)はWPF、Silverlight、Windows PhoneそしてWindows Store appsでユーザーインターフェースを定義するために使われるXML言語です。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

1グッド

0クリップ

投稿2020/10/05 13:00

#質問内容
RelativeSourceを使うと、親要素までさかのぼってWindowのDataContextを使うことができますが、
以下のようにContextMenuを挟むとうまくBindされません。
イメージ説明

FizのほうはBindされますが、
BizのほうはBindされません。

何か解決策がありましたら、ご教授いただきたいです。
よろしくお願いいたします。

※実際にはCommandをBindさせたいと考えていますが、質問内容を簡潔にするためにHeaderにStringをBindしています。

#コード
正確なコードは以下の通りです。

XAML

1<Window x:Class="TestWpfApp.Views.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:vm="clr-namespace:TestWpfApp.ViewModels" 7 mc:Ignorable="d" 8 Title="MainWindow" Height="450" Width="800"> 9 10 <Window.DataContext> 11 <vm:MainVM/> 12 </Window.DataContext> 13 14 <ListBox ItemsSource="{Binding MyList}"> 15 <ListBox.ItemTemplate> 16 <DataTemplate> 17 <Expander> 18 <Expander.ContextMenu> 19 <ContextMenu> 20 <MenuItem Header="{ 21 Binding Path=DataContext.Biz, 22 RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"/> 23 </ContextMenu> 24 </Expander.ContextMenu> 25 <Expander.Header> 26 <TextBlock Text="{Binding}"/> 27 </Expander.Header> 28 <Button Content="{ 29 Binding Path=DataContext.Fiz, 30 RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"/> 31 </Expander> 32 </DataTemplate> 33 </ListBox.ItemTemplate> 34 </ListBox> 35</Window>

C#

1using System.Collections.Generic; 2 3namespace TestWpfApp.ViewModels 4{ 5 class MainVM 6 { 7 public MainVM() => this.MyList.Add("hoge"); 8 9 public string Biz { get; } = "Biz"; 10 public string Fiz { get; } = "Fiz"; 11 12 public List<string> MyList { get; } = new List<string>(); 13 } 14}
TN8001👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

WPFのイヤなところなのですが、ContextMenuVisualTreeが繋がっておらず単純にはFindAncestorが効きません。

  • PlacementTargetTagの組み合わせ
  • BindingProxy

の2つがよくある解決法です。

xml

1<Window 2 x:Class="Questions296143.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:local="clr-namespace:Questions296143" 6 Width="800" 7 Height="450"> 8 <Window.DataContext> 9 <local:MainVM /> 10 </Window.DataContext> 11 <Window.Resources> 12 <local:BindingProxy x:Key="proxy" Data="{Binding}" /> 13 </Window.Resources> 14 <Grid> 15 <ListBox ItemsSource="{Binding MyList}"> 16 <ListBox.ItemTemplate> 17 <DataTemplate> 18 <UniformGrid Rows="1"> 19 20 <GroupBox Header="Original"> 21 <Button Content="{Binding DataContext.Fiz, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"> 22 <Button.ContextMenu> 23 <ContextMenu> 24 <MenuItem Header="{Binding DataContext.Biz, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" /> 25 </ContextMenu> 26 </Button.ContextMenu> 27 </Button> 28 </GroupBox> 29 30 <!-- Tag xamlのみで済むが、パット見何してるかわかりにくい --> 31 <GroupBox Header="Tag"> 32 <Button 33 Content="{Binding DataContext.Fiz, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" 34 Tag="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"> 35 <Button.ContextMenu> 36 <ContextMenu> 37 <MenuItem Header="{Binding PlacementTarget.Tag.Biz, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}" /> 38 </ContextMenu> 39 40 <!-- あるいは --> 41 <!--<ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}"> 42 <MenuItem Header="{Binding Biz}" /> 43 </ContextMenu>--> 44 </Button.ContextMenu> 45 </Button> 46 </GroupBox> 47 48 <!-- BindingProxy C#コードが必要だが、xamlはスッキリ --> 49 <GroupBox Header="BindingProxy"> 50 <Button Content="{Binding DataContext.Fiz, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"> 51 <Button.ContextMenu> 52 <ContextMenu> 53 <MenuItem Header="{Binding Data.Biz, Source={StaticResource proxy}}" /> 54 </ContextMenu> 55 </Button.ContextMenu> 56 </Button> 57 </GroupBox> 58 59 <!-- AncestorLevelとかの話ではない。ツリーが繋がってないので出るわけがない! --> 60 <GroupBox Header="takapi__cs"> 61 <Button Content="{Binding DataContext.Fiz, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"> 62 <Button.ContextMenu> 63 <ContextMenu> 64 <MenuItem Header="{Binding DataContext.Biz, RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType=Window}}" /> 65 </ContextMenu> 66 </Button.ContextMenu> 67 </Button> 68 </GroupBox> 69 </UniformGrid> 70 </DataTemplate> 71 </ListBox.ItemTemplate> 72 </ListBox> 73 </Grid> 74</Window>

cs

1using System.Collections.Generic; 2using System.Windows; 3 4namespace Questions296143 5{ 6 class BindingProxy : Freezable 7 { 8 public object Data { get => GetValue(DataProperty); set => SetValue(DataProperty, value); } 9 public static readonly DependencyProperty DataProperty 10 = DependencyProperty.Register(nameof(Data), typeof(object), typeof(BindingProxy), 11 new PropertyMetadata(null)); 12 13 protected override Freezable CreateInstanceCore() => new BindingProxy(); 14 } 15 16 class MainVM 17 { 18 public string Biz { get; } = "Biz"; 19 public string Fiz { get; } = "Fiz"; 20 public List<string> MyList { get; } = new List<string> { "hoge" }; 21 } 22 23 public partial class MainWindow : Window 24 { 25 public MainWindow() => InitializeComponent(); 26 } 27}

投稿2020/10/05 15:19

編集2023/07/09 01:20
TN8001

総合スコア9862

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

OZONE

2020/10/06 09:24

両方の方法でうまく行うことができました。 回答ありがとうございます。
guest

0

AncestorType箇所の書き方をIntellisenseに従って下記のように実装してみたら表示されました。

追記
.NET Frameworkでも確認してみました。
AncestorLevelの設定を加えれば表示されましたので、こちらも試してみてください。

Xaml

1<MenuItem Header="{Binding DataContext.Biz, RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType=Window}}" />

RelativeSource.AncestorLevel プロパティ

投稿2020/10/05 13:47

編集2020/10/05 14:38
takapi_cs

総合スコア349

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

OZONE

2020/10/05 14:24

ご提示いただいたコードを使ってみましたが、相変わらず表示されませんでした。 そちらでは表示されたとのことでしたので、環境的なものでしょうか? こちら.NET Framework 4.8 。Nugetパッケージなど外部ライブラリは未使用です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問