回答編集履歴

2

見直しキャンペーン中

2023/08/13 12:12

投稿

TN8001
TN8001

スコア9326

test CHANGED
@@ -1,7 +1,7 @@
1
- `MahApps.Metro`の`MetroTabControl`が、`TabItem`のキャッシュに対応していました(ちゃんとやるとなるとxamlも長くなるし、正しく書く自信もないのでどうしようかと思っていたところでした^^;
1
+ MahApps.Metroの`MetroTabControl`が、`TabItem`のキャッシュに対応していました(ちゃんとやるとなるとxamlも長くなるし、正しく書く自信もないのでどうしようかと思っていたところでした^^;
2
2
  [NuGet Gallery | MahApps.Metro 2.4.3](https://www.nuget.org/packages/MahApps.Metro/2.4.3?_src=template)
3
3
 
4
- もしくは`MetroTabControl`が依存している、`ControlzEx`の`TabControlEx`でもいいと思います(未確認)
4
+ もしくは`MetroTabControl`が依存している、ControlzExの`TabControlEx`でもいいと思います(未確認)
5
5
  [NuGet Gallery | ControlzEx 4.4.0](https://www.nuget.org/packages/ControlzEx/)
6
6
  [TabControlEx](https://github.com/ControlzEx/ControlzEx#tabcontrolex)
7
7
 

1

見直しキャンペーン中

2023/07/26 13:32

投稿

TN8001
TN8001

スコア9326

test CHANGED
@@ -1,347 +1,174 @@
1
1
  `MahApps.Metro`の`MetroTabControl`が、`TabItem`のキャッシュに対応していました(ちゃんとやるとなるとxamlも長くなるし、正しく書く自信もないのでどうしようかと思っていたところでした^^;
2
-
3
2
  [NuGet Gallery | MahApps.Metro 2.4.3](https://www.nuget.org/packages/MahApps.Metro/2.4.3?_src=template)
4
3
 
5
-
6
-
7
4
  もしくは`MetroTabControl`が依存している、`ControlzEx`の`TabControlEx`でもいいと思います(未確認)
8
-
9
5
  [NuGet Gallery | ControlzEx 4.4.0](https://www.nuget.org/packages/ControlzEx/)
10
-
11
6
  [TabControlEx](https://github.com/ControlzEx/ControlzEx#tabcontrolex)
12
7
 
13
-
14
-
15
8
  やっていることは↓とほぼ同じなので、ライブラリを使用したくない場合はこれをベースにしてください(ちょっと甘いところがあるので要調整)
16
-
17
9
  [c# - Stop TabControl from recreating its children - Stack Overflow](https://stackoverflow.com/questions/9794151/stop-tabcontrol-from-recreating-its-children/9802346#9802346)
18
10
 
19
11
 
20
-
21
-
22
-
23
12
  次はフォーカスですが↓はベタ置き専用になっていますので、`ItemsSource`と両対応&添付ビヘイビア化しました。
24
-
25
13
  [TabControlでのTab切り替え時フォーカス設定](https://social.msdn.microsoft.com/Forums/ja-JP/e1f77d05-3358-4d63-8810-165300b22f24/tabcontrol1239112398tab209991242626367123602617812501124571254012459?forum=wpfja)
26
-
27
-
28
14
 
29
15
  簡単に試した限りは動いていますが、突っ込んだテストはしていません(間違えるほど大したことはしていないので、大丈夫だとは思いますが^^;
30
16
 
31
-
32
-
33
- ```xaml
17
+ ```xml
34
-
35
18
  <Window
36
-
37
19
  x:Class="Questions318528.MainWindow"
38
-
39
20
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
40
-
41
21
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
42
-
43
22
  xmlns:local="clr-namespace:Questions318528"
44
-
45
23
  xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
46
-
47
24
  Width="800"
48
-
49
25
  Height="450">
50
-
51
26
  <Grid>
52
-
53
27
  <mah:MetroTabControl
54
-
55
28
  local:TabItemKeepFocusBehavior.Use="True"
56
-
57
29
  ItemsSource="{Binding Tabs}"
58
-
59
30
  KeepVisualTreeInMemoryWhenChangingTabs="True">
60
-
61
31
  <TabControl.Resources>
62
-
63
32
  <DataTemplate DataType="{x:Type local:TabItem1}">
64
-
65
33
  <ScrollViewer>
66
-
67
34
  <StackPanel>
68
-
69
35
  <TextBlock Text="View1" />
70
-
71
36
  <TextBox />
72
-
73
37
  <Image Source="https://teratail-v2.storage.googleapis.com/uploads/avatars/u13/132786/KnkDDC5A_thumbnail.jpg" />
74
-
75
38
  <TextBox />
76
-
77
39
  <Image Source="https://teratail-v2.storage.googleapis.com/uploads/avatars/u13/132786/KnkDDC5A_thumbnail.jpg" />
78
-
79
40
  <TextBox />
80
-
81
41
  </StackPanel>
82
-
83
42
  </ScrollViewer>
84
-
85
43
  </DataTemplate>
86
-
87
44
  <DataTemplate DataType="{x:Type local:TabItem2}">
88
-
89
45
  <ScrollViewer>
90
-
91
46
  <StackPanel>
92
-
93
47
  <TextBlock Text="View2" />
94
-
95
48
  <TextBox />
96
-
97
49
  <Image Source="https://teratail-v2.storage.googleapis.com/uploads/avatars/u13/132786/KnkDDC5A_thumbnail.jpg" />
98
-
99
50
  <TextBox />
100
-
101
51
  <Image Source="https://teratail-v2.storage.googleapis.com/uploads/avatars/u13/132786/KnkDDC5A_thumbnail.jpg" />
102
-
103
52
  <TextBox />
104
-
105
53
  </StackPanel>
106
-
107
54
  </ScrollViewer>
108
-
109
55
  </DataTemplate>
110
-
111
56
  </TabControl.Resources>
112
-
113
57
  <TabControl.ItemTemplate>
114
-
115
58
  <DataTemplate>
116
-
117
59
  <TextBlock Text="header" />
118
-
119
60
  </DataTemplate>
120
-
121
61
  </TabControl.ItemTemplate>
122
-
123
62
  </mah:MetroTabControl>
124
-
125
63
  </Grid>
126
-
127
64
  </Window>
128
-
129
65
  ```
130
66
 
131
-
132
-
133
- ```C#
67
+ ```cs
134
-
135
68
  using System;
136
-
137
69
  using System.Collections.ObjectModel;
138
-
139
70
  using System.Windows;
140
-
141
71
  using System.Windows.Controls;
142
-
143
72
  using System.Windows.Input;
144
-
145
73
  using System.Windows.Threading;
146
74
 
147
-
148
-
149
75
  namespace Questions318528
150
-
151
76
  {
152
-
153
77
  public class TabItem1 { }
154
-
155
78
  public class TabItem2 { }
156
79
 
157
-
158
-
159
80
  public partial class MainWindow : Window
160
-
161
81
  {
162
-
163
82
  public ObservableCollection<object> Tabs { get; }
164
-
165
83
  public MainWindow()
166
-
167
84
  {
168
-
169
85
  InitializeComponent();
170
-
171
86
  DataContext = this;
172
87
 
88
+ Tabs = new()
89
+ {
90
+ new TabItem1(),
91
+ new TabItem2(),
92
+ "aaa",
93
+ };
94
+ }
95
+ }
173
96
 
97
+ // [TabControlでのTab切り替え時フォーカス設定](https://social.msdn.microsoft.com/Forums/ja-JP/e1f77d05-3358-4d63-8810-165300b22f24/tabcontrol1239112398tab209991242626367123602617812501124571254012459?forum=wpfja)
98
+ // を参考に添付ビヘイビア化
99
+ internal class TabItemKeepFocusBehavior
100
+ {
101
+ // 内部使用添付プロパティ TabItemに添付 フォーカスがあったエレメント
102
+ private static readonly DependencyProperty FocusedProperty
103
+ = DependencyProperty.RegisterAttached("Focused", typeof(IInputElement), typeof(TabItemKeepFocusBehavior),
104
+ new PropertyMetadata(null));
105
+ private static IInputElement GetFocused(DependencyObject target) => (IInputElement)target.GetValue(FocusedProperty);
106
+ private static void SetFocused(DependencyObject target, IInputElement value) => target.SetValue(FocusedProperty, value);
174
107
 
108
+ // 添付ビヘイビア TabControlに添付 フォーカス戻しを使用するかどうか
109
+ public static readonly DependencyProperty UseProperty
110
+ = DependencyProperty.RegisterAttached("Use", typeof(bool), typeof(TabItemKeepFocusBehavior),
175
- Tabs = new()
111
+ new PropertyMetadata(false, OnUseChanged));
112
+ public static bool GetUse(DependencyObject target) => (bool)target.GetValue(UseProperty);
113
+ public static void SetUse(DependencyObject target, bool value) => target.SetValue(UseProperty, value);
176
114
 
115
+ private static void OnUseChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
116
+ {
117
+ if (sender is TabControl tabControl)
177
118
  {
178
-
179
- new TabItem1(),
119
+ if ((bool)e.NewValue)
180
-
120
+ {
121
+ tabControl.PreviewGotKeyboardFocus += TabControl_PreviewGotKeyboardFocus;
181
- new TabItem2(),
122
+ tabControl.SelectionChanged += TabControl_SelectionChanged;
182
-
183
- "aaa",
184
-
185
- };
123
+ }
186
-
124
+ else
125
+ {
126
+ tabControl.PreviewGotKeyboardFocus -= TabControl_PreviewGotKeyboardFocus;
127
+ tabControl.SelectionChanged -= TabControl_SelectionChanged;
128
+ }
129
+ }
187
130
  }
188
131
 
132
+ // フォーカスを得るたびにFocusedにセット
133
+ private static void TabControl_PreviewGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
189
- }
134
+ {
135
+ if (sender is TabControl tabControl)
136
+ {
137
+ if (e.NewFocus is TabItem) return;
190
138
 
139
+ var tabItem = tabControl.SelectedItem as TabItem ?? tabControl.ItemContainerGenerator.ContainerFromItem(tabControl.SelectedItem) as TabItem;
140
+ if (tabItem == null) return;
191
141
 
192
-
193
- // [TabControlでのTab切り替え時フォーカス設定](https://social.msdn.microsoft.com/Forums/ja-JP/e1f77d05-3358-4d63-8810-165300b22f24/tabcontrol1239112398tab209991242626367123602617812501124571254012459?forum=wpfja)
194
-
195
- // を参考に添付ビヘイビア化
196
-
197
- internal class TabItemKeepFocusBehavior
198
-
199
- {
200
-
201
- // 内部使用添付プロパティ TabItemに添付 フォーカスがあったエレメント
202
-
203
- private static readonly DependencyProperty FocusedProperty
204
-
205
- = DependencyProperty.RegisterAttached("Focused", typeof(IInputElement), typeof(TabItemKeepFocusBehavior),
206
-
207
- new PropertyMetadata(null));
208
-
209
- private static IInputElement GetFocused(DependencyObject target) => (IInputElement)target.GetValue(FocusedProperty);
210
-
211
- private static void SetFocused(DependencyObject target, IInputElement value) => target.SetValue(FocusedProperty, value);
212
-
213
-
214
-
215
- // 添付ビヘイビア TabControlに添付 フォーカス戻しを使用するかどうか
216
-
217
- public static readonly DependencyProperty UseProperty
218
-
219
- = DependencyProperty.RegisterAttached("Use", typeof(bool), typeof(TabItemKeepFocusBehavior),
220
-
221
- new PropertyMetadata(false, OnUseChanged));
222
-
223
- public static bool GetUse(DependencyObject target) => (bool)target.GetValue(UseProperty);
224
-
225
- public static void SetUse(DependencyObject target, bool value) => target.SetValue(UseProperty, value);
226
-
227
-
228
-
229
- private static void OnUseChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
230
-
231
- {
232
-
233
- if (sender is TabControl tabControl)
234
-
235
- {
236
-
237
- if ((bool)e.NewValue)
238
-
142
+ if (e.NewFocus is IInputElement element)
239
143
  {
240
-
241
- tabControl.PreviewGotKeyboardFocus += TabControl_PreviewGotKeyboardFocus;
242
-
243
- tabControl.SelectionChanged += TabControl_SelectionChanged;
144
+ SetFocused(tabItem, element);
244
-
245
145
  }
246
-
247
- else
248
-
249
- {
250
-
251
- tabControl.PreviewGotKeyboardFocus -= TabControl_PreviewGotKeyboardFocus;
252
-
253
- tabControl.SelectionChanged -= TabControl_SelectionChanged;
254
-
255
- }
256
-
257
146
  }
258
-
259
147
  }
260
148
 
261
-
262
-
263
- // フォーカスを得るにFocusedにセット
149
+ // 選択が変わっときにFocusedにフォーカス
264
-
265
- private static void TabControl_PreviewGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
150
+ private static void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
266
-
267
151
  {
268
-
269
152
  if (sender is TabControl tabControl)
270
-
271
153
  {
272
-
273
- if (e.NewFocus is TabItem) return;
274
-
275
-
276
-
277
154
  var tabItem = tabControl.SelectedItem as TabItem ?? tabControl.ItemContainerGenerator.ContainerFromItem(tabControl.SelectedItem) as TabItem;
278
-
279
155
  if (tabItem == null) return;
280
156
 
281
-
282
-
283
- if (e.NewFocus is IInputElement element)
157
+ if (GetFocused(tabItem) is IInputElement element)
284
-
285
158
  {
286
-
287
- SetFocused(tabItem, element);
159
+ Action action = () => element.Focus();
288
-
160
+ tabControl.Dispatcher.BeginInvoke(action, DispatcherPriority.Input);
289
161
  }
290
-
291
162
  }
292
-
293
163
  }
294
-
295
-
296
-
297
- // 選択が変わったときにFocusedにフォーカス
298
-
299
- private static void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
300
-
301
- {
302
-
303
- if (sender is TabControl tabControl)
304
-
305
- {
306
-
307
- var tabItem = tabControl.SelectedItem as TabItem ?? tabControl.ItemContainerGenerator.ContainerFromItem(tabControl.SelectedItem) as TabItem;
308
-
309
- if (tabItem == null) return;
310
-
311
-
312
-
313
- if (GetFocused(tabItem) is IInputElement element)
314
-
315
- {
316
-
317
- Action action = () => element.Focus();
318
-
319
- tabControl.Dispatcher.BeginInvoke(action, DispatcherPriority.Input);
320
-
321
- }
322
-
323
- }
324
-
325
- }
326
-
327
164
  }
328
-
329
165
  }
330
-
331
166
  ```
332
-
333
-
334
167
 
335
168
  ---
336
169
 
337
-
338
-
339
170
  特に指定がないので.NET 5.0で書きました^^
340
-
341
171
  .NET Framework 4.8等では、new()でエラーが出るので型を書いてください。
342
172
 
343
-
344
-
345
173
  [Target-typed new expressions - C# 9.0 specification proposals | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/proposals/csharp-9.0/target-typed-new)
346
-
347
174
  [ターゲットからの new 型推論 | ++C++; // 未確認飛行 C](https://ufcpp.net/study/csharp/oo_construct.html#target-typed-new)