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

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

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

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

WPF

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

Q&A

解決済

1回答

5089閲覧

TabControl内のTabItemを使いまわすには?(WPF)

fijino

総合スコア136

C#

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

WPF

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

1グッド

0クリップ

投稿2021/01/26 02:11

編集2023/08/13 21:12

xaml

1<TabControl ItemsSource="{Binding Tabs}"> 2 <TabControl.Resources> 3 <DataTemplate DataType="{x:Ttpe local:TabItem1}" > 4 <local:View1 /> 5 </DataTemplate > 6 <DataTemplate DataType="{x:Ttpe local:TabItem2}" > 7 <local:View2 /> 8 </DataTemplate > 9 </TabControl.Resources> 10 <TabControl.ItemTemplate> 11 <DataTemplate> 12 <TextBlock text="header" /> 13 </DataTemplate> 14 </TabControl.ItemTemplate> 15</TabControl>

TabControlの表示内容をItemの種類により切り替えたく、ResourcesにDataTemplateを設定しました。
これでItemの種類毎に表示内容が切り替わるのですが、Tabを切り替える毎にViewが新しく作成されてしまいます。

そのため、スクロールやキャレットが元にもどってしまうのですが、Tabを切り替えてもViewを新しく作成するのではなく使いまわして
スクロールやキャレットが元に戻らないようにするにはどうすれば良いでしょうか。

TN8001👍を押しています

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

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

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

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

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

TN8001

2021/01/26 14:19

TabItemをキャッシュするソリューションはググればすぐ出てきますが、キーボードフォーカスまで戻すのはないですね^^; タブは不定個なのでしょうか? 固定であれば(TabControl.Itemsに突っ込める場合は)↓こんな感じで自分で設定すればよさそうです。 [TabControlでのTab切り替え時フォーカス設定](https://social.msdn.microsoft.com/Forums/ja-JP/e1f77d05-3358-4d63-8810-165300b22f24/tabcontroltab?forum=wpfja 不定個の場合は、TabItemをキャッシュするソリューション(例えば↓こんなの) [wpf - How to preserve control state within tab items in a TabControl - Stack Overflow](https://stackoverflow.com/questions/2080764/how-to-preserve-control-state-within-tab-items-in-a-tabcontrol と、組み合わせれば理屈上はいけますがなんだかごちゃごちゃしますねぇ。 もっと簡単にできないか考えているのですが、フォーカス周りは難しくてこれといった方法を思いつけていません。。。
fijino

2021/01/27 01:00

メニューに選んだものがTabItemとして追加されるためTabItemは不定個です。 リンク先を少し読ませていただきましたが、簡単ではなさそうですね。 ご紹介のリンク先を参考に試行錯誤したいと思います。 ご回答ありがとうございました。
guest

回答1

0

ベストアンサー

MahApps.MetroのMetroTabControlが、TabItemのキャッシュに対応していました(ちゃんとやるとなるとxamlも長くなるし、正しく書く自信もないのでどうしようかと思っていたところでした^^;
NuGet Gallery | MahApps.Metro 2.4.3

もしくはMetroTabControlが依存している、ControlzExのTabControlExでもいいと思います(未確認)
NuGet Gallery | ControlzEx 4.4.0
TabControlEx

やっていることは↓とほぼ同じなので、ライブラリを使用したくない場合はこれをベースにしてください(ちょっと甘いところがあるので要調整)
c# - Stop TabControl from recreating its children - Stack Overflow

次はフォーカスですが↓はベタ置き専用になっていますので、ItemsSourceと両対応&添付ビヘイビア化しました。
TabControlでのTab切り替え時フォーカス設定

簡単に試した限りは動いていますが、突っ込んだテストはしていません(間違えるほど大したことはしていないので、大丈夫だとは思いますが^^;

xml

1<Window 2 x:Class="Questions318528.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:Questions318528" 6 xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls" 7 Width="800" 8 Height="450"> 9 <Grid> 10 <mah:MetroTabControl 11 local:TabItemKeepFocusBehavior.Use="True" 12 ItemsSource="{Binding Tabs}" 13 KeepVisualTreeInMemoryWhenChangingTabs="True"> 14 <TabControl.Resources> 15 <DataTemplate DataType="{x:Type local:TabItem1}"> 16 <ScrollViewer> 17 <StackPanel> 18 <TextBlock Text="View1" /> 19 <TextBox /> 20 <Image Source="https://teratail-v2.storage.googleapis.com/uploads/avatars/u13/132786/KnkDDC5A_thumbnail.jpg" /> 21 <TextBox /> 22 <Image Source="https://teratail-v2.storage.googleapis.com/uploads/avatars/u13/132786/KnkDDC5A_thumbnail.jpg" /> 23 <TextBox /> 24 </StackPanel> 25 </ScrollViewer> 26 </DataTemplate> 27 <DataTemplate DataType="{x:Type local:TabItem2}"> 28 <ScrollViewer> 29 <StackPanel> 30 <TextBlock Text="View2" /> 31 <TextBox /> 32 <Image Source="https://teratail-v2.storage.googleapis.com/uploads/avatars/u13/132786/KnkDDC5A_thumbnail.jpg" /> 33 <TextBox /> 34 <Image Source="https://teratail-v2.storage.googleapis.com/uploads/avatars/u13/132786/KnkDDC5A_thumbnail.jpg" /> 35 <TextBox /> 36 </StackPanel> 37 </ScrollViewer> 38 </DataTemplate> 39 </TabControl.Resources> 40 <TabControl.ItemTemplate> 41 <DataTemplate> 42 <TextBlock Text="header" /> 43 </DataTemplate> 44 </TabControl.ItemTemplate> 45 </mah:MetroTabControl> 46 </Grid> 47</Window>

cs

1using System; 2using System.Collections.ObjectModel; 3using System.Windows; 4using System.Windows.Controls; 5using System.Windows.Input; 6using System.Windows.Threading; 7 8namespace Questions318528 9{ 10 public class TabItem1 { } 11 public class TabItem2 { } 12 13 public partial class MainWindow : Window 14 { 15 public ObservableCollection<object> Tabs { get; } 16 public MainWindow() 17 { 18 InitializeComponent(); 19 DataContext = this; 20 21 Tabs = new() 22 { 23 new TabItem1(), 24 new TabItem2(), 25 "aaa", 26 }; 27 } 28 } 29 30 // [TabControlでのTab切り替え時フォーカス設定](https://social.msdn.microsoft.com/Forums/ja-JP/e1f77d05-3358-4d63-8810-165300b22f24/tabcontrol1239112398tab209991242626367123602617812501124571254012459?forum=wpfja) 31 // を参考に添付ビヘイビア化 32 internal class TabItemKeepFocusBehavior 33 { 34 // 内部使用添付プロパティ TabItemに添付 フォーカスがあったエレメント 35 private static readonly DependencyProperty FocusedProperty 36 = DependencyProperty.RegisterAttached("Focused", typeof(IInputElement), typeof(TabItemKeepFocusBehavior), 37 new PropertyMetadata(null)); 38 private static IInputElement GetFocused(DependencyObject target) => (IInputElement)target.GetValue(FocusedProperty); 39 private static void SetFocused(DependencyObject target, IInputElement value) => target.SetValue(FocusedProperty, value); 40 41 // 添付ビヘイビア TabControlに添付 フォーカス戻しを使用するかどうか 42 public static readonly DependencyProperty UseProperty 43 = DependencyProperty.RegisterAttached("Use", typeof(bool), typeof(TabItemKeepFocusBehavior), 44 new PropertyMetadata(false, OnUseChanged)); 45 public static bool GetUse(DependencyObject target) => (bool)target.GetValue(UseProperty); 46 public static void SetUse(DependencyObject target, bool value) => target.SetValue(UseProperty, value); 47 48 private static void OnUseChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 49 { 50 if (sender is TabControl tabControl) 51 { 52 if ((bool)e.NewValue) 53 { 54 tabControl.PreviewGotKeyboardFocus += TabControl_PreviewGotKeyboardFocus; 55 tabControl.SelectionChanged += TabControl_SelectionChanged; 56 } 57 else 58 { 59 tabControl.PreviewGotKeyboardFocus -= TabControl_PreviewGotKeyboardFocus; 60 tabControl.SelectionChanged -= TabControl_SelectionChanged; 61 } 62 } 63 } 64 65 // フォーカスを得るたびにFocusedにセット 66 private static void TabControl_PreviewGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) 67 { 68 if (sender is TabControl tabControl) 69 { 70 if (e.NewFocus is TabItem) return; 71 72 var tabItem = tabControl.SelectedItem as TabItem ?? tabControl.ItemContainerGenerator.ContainerFromItem(tabControl.SelectedItem) as TabItem; 73 if (tabItem == null) return; 74 75 if (e.NewFocus is IInputElement element) 76 { 77 SetFocused(tabItem, element); 78 } 79 } 80 } 81 82 // 選択が変わったときにFocusedにフォーカス 83 private static void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e) 84 { 85 if (sender is TabControl tabControl) 86 { 87 var tabItem = tabControl.SelectedItem as TabItem ?? tabControl.ItemContainerGenerator.ContainerFromItem(tabControl.SelectedItem) as TabItem; 88 if (tabItem == null) return; 89 90 if (GetFocused(tabItem) is IInputElement element) 91 { 92 Action action = () => element.Focus(); 93 tabControl.Dispatcher.BeginInvoke(action, DispatcherPriority.Input); 94 } 95 } 96 } 97 } 98}

特に指定がないので.NET 5.0で書きました^^
.NET Framework 4.8等では、new()でエラーが出るので型を書いてください。

Target-typed new expressions - C# 9.0 specification proposals | Microsoft Docs
ターゲットからの new 型推論 | ++C++; // 未確認飛行 C

投稿2021/01/27 01:05

編集2023/08/13 12:12
TN8001

総合スコア9244

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

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

fijino

2021/01/27 01:51

おかげさまで全て上手くいきました! 簡単に出来るのかと思っていたら、こんなに色々やらないとダメだったんですね。 勉強になりました、ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問