回答編集履歴

1

後から見て意図がわからなかったので、わかりやすく書き直し

2023/07/09 01:20

投稿

TN8001
TN8001

スコア9357

test CHANGED
@@ -1,171 +1,113 @@
1
1
  WPFのイヤなところなのですが、`ContextMenu`は`VisualTree`が繋がっておらず単純には`FindAncestor`が効きません。
2
2
 
3
-
4
-
5
3
  * `PlacementTarget`と`Tag`の組み合わせ
6
-
7
4
  * `BindingProxy`
8
-
9
-
10
5
 
11
6
  の2つがよくある解決法です。
12
7
 
8
+ ```xml
9
+ <Window
10
+ x:Class="Questions296143.MainWindow"
11
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
12
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
13
+ xmlns:local="clr-namespace:Questions296143"
14
+ Width="800"
15
+ Height="450">
16
+ <Window.DataContext>
17
+ <local:MainVM />
18
+ </Window.DataContext>
19
+ <Window.Resources>
20
+ <local:BindingProxy x:Key="proxy" Data="{Binding}" />
21
+ </Window.Resources>
22
+ <Grid>
23
+ <ListBox ItemsSource="{Binding MyList}">
24
+ <ListBox.ItemTemplate>
25
+ <DataTemplate>
26
+ <UniformGrid Rows="1">
13
27
 
28
+ <GroupBox Header="Original">
29
+ <Button Content="{Binding DataContext.Fiz, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">
30
+ <Button.ContextMenu>
31
+ <ContextMenu>
32
+ <MenuItem Header="{Binding DataContext.Biz, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />
33
+ </ContextMenu>
34
+ </Button.ContextMenu>
35
+ </Button>
36
+ </GroupBox>
14
37
 
38
+ <!-- Tag xamlのみで済むが、パット見何してるかわかりにくい -->
39
+ <GroupBox Header="Tag">
15
- ```xaml
40
+ <Button
41
+ Content="{Binding DataContext.Fiz, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
42
+ Tag="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">
43
+ <Button.ContextMenu>
44
+ <ContextMenu>
45
+ <MenuItem Header="{Binding PlacementTarget.Tag.Biz, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}" />
46
+ </ContextMenu>
47
+
48
+ <!-- あるいは -->
49
+ <!--<ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
50
+ <MenuItem Header="{Binding Biz}" />
51
+ </ContextMenu>-->
52
+ </Button.ContextMenu>
53
+ </Button>
54
+ </GroupBox>
16
55
 
56
+ <!-- BindingProxy C#コードが必要だが、xamlはスッキリ -->
57
+ <GroupBox Header="BindingProxy">
58
+ <Button Content="{Binding DataContext.Fiz, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">
59
+ <Button.ContextMenu>
17
- <Window
60
+ <ContextMenu>
61
+ <MenuItem Header="{Binding Data.Biz, Source={StaticResource proxy}}" />
62
+ </ContextMenu>
63
+ </Button.ContextMenu>
64
+ </Button>
65
+ </GroupBox>
18
66
 
19
- x:Class="Questions296143.MainWindow"
20
-
21
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
22
-
23
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
24
-
25
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
26
-
27
- xmlns:local="clr-namespace:Questions296143"
28
-
29
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
30
-
31
- Title="MainWindow"
32
-
33
- Width="800"
34
-
35
- Height="450"
36
-
37
- mc:Ignorable="d">
38
-
39
- <Window.DataContext>
40
-
41
- <local:MainVM />
42
-
43
- </Window.DataContext>
44
-
45
- <Window.Resources>
46
-
47
- <local:BindingProxy x:Key="proxy" Data="{Binding}" />
48
-
49
- </Window.Resources>
50
-
51
- <ListBox ItemsSource="{Binding MyList}">
67
+ <!-- AncestorLevelとかの話ではない。ツリーが繋がってないので出るわけがない! -->
52
-
53
- <ListBox.ItemTemplate>
54
-
55
- <DataTemplate>
56
-
57
- <StackPanel>
58
-
59
- <Button Content="Original">
68
+ <GroupBox Header="takapi__cs">
60
-
69
+ <Button Content="{Binding DataContext.Fiz, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">
61
- <Button.ContextMenu>
70
+ <Button.ContextMenu>
62
-
63
- <ContextMenu>
71
+ <ContextMenu>
64
-
65
- <MenuItem Header="{Binding Path=DataContext.Biz, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />
72
+ <MenuItem Header="{Binding DataContext.Biz, RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType=Window}}" />
66
-
67
- </ContextMenu>
73
+ </ContextMenu>
68
-
69
- </Button.ContextMenu>
74
+ </Button.ContextMenu>
70
-
71
- </Button>
75
+ </Button>
72
-
73
- <Button Content="Tag" Tag="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">
74
-
75
- <Button.ContextMenu>
76
-
77
- <ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
78
-
79
- <MenuItem Header="{Binding Path=Biz}" />
80
-
81
- </ContextMenu>
82
-
83
- </Button.ContextMenu>
84
-
85
- </Button>
76
+ </GroupBox>
86
-
87
- <Button Content="BindingProxy">
88
-
89
- <Button.ContextMenu>
90
-
91
- <ContextMenu>
92
-
93
- <MenuItem Header="{Binding Path=Data.Biz, Source={StaticResource proxy}}" />
94
-
95
- </ContextMenu>
77
+ </UniformGrid>
96
-
97
- </Button.ContextMenu>
98
-
99
- </Button>
100
-
101
- </StackPanel>
102
-
103
- </DataTemplate>
78
+ </DataTemplate>
104
-
105
- </ListBox.ItemTemplate>
79
+ </ListBox.ItemTemplate>
106
-
107
- </ListBox>
80
+ </ListBox>
108
-
81
+ </Grid>
109
82
  </Window>
110
-
111
83
  ```
112
84
 
113
-
114
-
115
- ```C#
85
+ ```cs
116
-
117
86
  using System.Collections.Generic;
118
-
119
87
  using System.Windows;
120
88
 
121
-
122
-
123
89
  namespace Questions296143
124
-
125
90
  {
126
-
127
91
  class BindingProxy : Freezable
128
-
129
92
  {
130
-
131
93
  public object Data { get => GetValue(DataProperty); set => SetValue(DataProperty, value); }
132
-
133
94
  public static readonly DependencyProperty DataProperty
134
-
135
95
  = DependencyProperty.Register(nameof(Data), typeof(object), typeof(BindingProxy),
136
-
137
96
  new PropertyMetadata(null));
138
97
 
139
-
140
-
141
98
  protected override Freezable CreateInstanceCore() => new BindingProxy();
142
-
143
99
  }
144
100
 
145
-
146
-
147
101
  class MainVM
148
-
149
102
  {
150
-
151
103
  public string Biz { get; } = "Biz";
152
-
153
104
  public string Fiz { get; } = "Fiz";
154
-
155
105
  public List<string> MyList { get; } = new List<string> { "hoge" };
156
-
157
106
  }
158
107
 
159
-
160
-
161
108
  public partial class MainWindow : Window
162
-
163
109
  {
164
-
165
110
  public MainWindow() => InitializeComponent();
166
-
167
111
  }
168
-
169
112
  }
170
-
171
113
  ```