ユーザーの選択に従って、タブページを表示または非表示にしようとしています。ユーザーが性別男性を選択した場合、タブページ「男性」の男性のフォームが表示され、ユーザーが女性を選択した場合、次のタブ「女性」に同様の次のフォームが表示されます。
使ってみた
tabControl1.TabPages.Remove(...)
そして
tabControl1.TabPages.Add(...)
それはタブページを追加および削除しますが、そうするとタブページのコントロールも失われます...私はそれらを見ることができません。ここの問題は何ですか?
TabControl.TabPagesコレクションからタブページを削除して、リストに保存できます。例えば:
private List<TabPage> hiddenPages = new List<TabPage>();
private void EnablePage(TabPage page, bool enable) {
if (enable) {
tabControl1.TabPages.Add(page);
hiddenPages.Remove(page);
}
else {
tabControl1.TabPages.Remove(page);
hiddenPages.Add(page);
}
}
protected override void OnFormClosed(FormClosedEventArgs e) {
foreach (var page in hiddenPages) page.Dispose();
base.OnFormClosed(e);
}
答えはずっと簡単だと思います。
タブを非表示にするには、TabPage自体を既に試した方法またはアドレス指定する方法を使用できます。
TabControl1.TabPages.Remove(TabPage1) 'Could be male
TabControl1.TabPages.Remove(TabPage2) 'Could be female
そう。
TabPageを削除しても、TabPageとそのコントロールは破壊されません。対応するタブを再度表示するには、次のコードを使用します
TabControl1.TabPages.Insert(0, TabPage1) 'Show male
TabControl1.TabPages.Insert(1, TabPage2) 'Show female
Hans Passantによる優れたソリューションの改善私は、彼のソリューションに基づいて拡張メソッドを記述し、他のものも追加することにしました。 .NET 4でも、この基本的な機能が修正されていないことに驚いています。
public static class TabPageExtensions
{
private struct TabPageData
{
internal int Index;
internal TabControl Parent;
internal TabPage Page;
internal TabPageData(int index, TabControl parent, TabPage page)
{
Index = index;
Parent = parent;
Page = page;
}
internal static string GetKey(TabControl tabCtrl, TabPage tabPage)
{
string key = "";
if (tabCtrl != null && tabPage != null)
{
key = String.Format("{0}:{1}", tabCtrl.Name, tabPage.Name);
}
return key;
}
}
private static Dictionary<string, TabPageData> hiddenPages = new Dictionary<string, TabPageData>();
public static void SetVisible(this TabPage page, TabControl parent)
{
if (parent != null && !parent.IsDisposed)
{
TabPageData tpinfo;
string key = TabPageData.GetKey(parent, page);
if (hiddenPages.ContainsKey(key))
{
tpinfo = hiddenPages[key];
if (tpinfo.Index < parent.TabPages.Count)
parent.TabPages.Insert(tpinfo.Index, tpinfo.Page); // add the page in the same position it had
else
parent.TabPages.Add(tpinfo.Page);
hiddenPages.Remove(key);
}
}
}
public static void SetInvisible(this TabPage page)
{
if (IsVisible(page))
{
TabControl tabCtrl = (TabControl)page.Parent;
TabPageData tpinfo;
tpinfo = new TabPageData(tabCtrl.TabPages.IndexOf(page), tabCtrl, page);
tabCtrl.TabPages.Remove(page);
hiddenPages.Add(TabPageData.GetKey(tabCtrl, page), tpinfo);
}
}
public static bool IsVisible(this TabPage page)
{
return page != null && page.Parent != null; // when Parent is null the tab page does not belong to any container
}
public static void CleanUpHiddenPages(this TabPage page)
{
foreach (TabPageData info in hiddenPages.Values)
{
if (info.Parent != null && info.Parent.Equals((TabControl)page.Parent))
info.Page.Dispose();
}
}
}
別のアプローチは、2つのタブコントロール、1つは表示、もう1つは表示しないことです。次のように、タブを一方から他方に移動できます(vb.net):
If Me.chkShowTab1.Checked = True Then
Me.tabsShown.TabPages.Add(Me.tabsHidden.TabPages("Tab1"))
Me.tabsHidden.TabPages.RemoveByKey("Tab1")
Else
Me.tabsHidden.TabPages.Add(Me.tabsShown.TabPages("Tab1"))
Me.tabsShown.TabPages.RemoveByKey("Tab1")
End If
タブの順序が重要な場合は、tabsShownの.Addメソッドを.Insertに変更し、順序位置を指定します。そのための1つの方法は、目的の順序位置を返すルーチンを呼び出すことです。
サンプルコードは動作していますが、リストのタブをより適切に参照したいです。
Public Class Form1
Dim State1 As Integer = 1
Dim AllTabs As List(Of TabPage) = New List(Of TabPage)
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Check1(State1)
State1 = CInt(IIf(State1 = 1, 0, 1))
End Sub
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
AllTabs.Add(TabControl1.TabPages("TabPage1"))
AllTabs.Add(TabControl1.TabPages("TabPage2"))
End Sub
Sub Check1(ByVal No As Integer)
If TabControl1.TabPages.ContainsKey("TabPage1") Then
TabControl1.TabPages.Remove(TabControl1.TabPages("TabPage1"))
End If
If TabControl1.TabPages.ContainsKey("TabPage2") Then
TabControl1.TabPages.Remove(TabControl1.TabPages("TabPage2"))
End If
TabControl1.TabPages.Add(AllTabs(No))
End Sub
End Class
public static Action<Func<TabPage, bool>> GetTabHider(this TabControl container) {
if (container == null) throw new ArgumentNullException("container");
var orderedCache = new List<TabPage>();
var orderedEnumerator = container.TabPages.GetEnumerator();
while (orderedEnumerator.MoveNext()) {
var current = orderedEnumerator.Current as TabPage;
if (current != null) {
orderedCache.Add(current);
}
}
return (Func<TabPage, bool> where) => {
if (where == null) throw new ArgumentNullException("where");
container.TabPages.Clear();
foreach (TabPage page in orderedCache) {
if (where(page)) {
container.TabPages.Add(page);
}
}
};
}
このように使用します:
var showOnly = this.TabContainer1.GetTabHider();
showOnly((tab) => tab.Text != "tabPage1");
匿名関数インスタンスへの参照を保持することにより、元の順序が保持されます。
私はフラットスタイルの外観を作ることを好みます: https://stackoverflow.com/a/25192153/5660876
tabControl1.Appearance = TabAppearance.FlatButtons;
tabControl1.ItemSize = new Size(0, 1);
tabControl1.SizeMode = TabSizeMode.Fixed;
ただし、すべてのtabPageにピクセルが表示されるため、すべてのtabpageのテキストをすべて削除すると、実行時にタブが完全に非表示になります。
foreach (TabPage tab in tabControl1.TabPages)
{
tab.Text = "";
}
その後、ツリービューを使用して、タブページを変更します...ノードをクリックします。
私はすべてのTabPagesをクリアし、希望するものを追加するのが簡単に見えます:
PropertyTabControl.TabPages.Clear();
PropertyTabControl.TabPages.Add(AspectTabPage);
PropertyTabControl.TabPages.Add(WerkstattTabPage);
または
PropertyTabControl.TabPages.Clear();
PropertyTabControl.TabPages.Add(TerminTabPage);
Tag
のTabPage
要素を使用する余裕がある場合は、この拡張メソッドを使用できます
public static void HideByRemoval(this TabPage tp)
{
TabControl tc = tp.Parent as TabControl;
if (tc != null && tc.TabPages.Contains(tp))
{
// Store TabControl and Index
tp.Tag = new Tuple<TabControl, Int32>(tc, tc.TabPages.IndexOf(tp));
tc.TabPages.Remove(tp);
}
}
public static void ShowByInsertion(this TabPage tp)
{
Tuple<TabControl, Int32> tagObj = tp.Tag as Tuple<TabControl, Int32>;
if (tagObj?.Item1 != null)
{
// Restore TabControl and Index
tagObj.Item1.TabPages.Insert(tagObj.Item2, tp);
}
}
タブの追加と削除は少し効果が低いかもしれません
タブページの表示/非表示を切り替える=> tabControl1のtabPage1を許可する
tapPage1.Parent = null; //to hide tabPage1 from tabControl1
tabPage1.Parent = tabControl1; //to show the tabPage1 in tabControl1
誰かがC#の回答をこの回答にマージしたので、ここに回答を投稿する必要があります。私は他のソリューションが好きではなかったので、タブの順序を維持しながらタブを非表示/表示しやすくするヘルパークラスを作成しました。
/// <summary>
/// Memorizes the order of tabs upon creation to make hiding / showing tabs more
/// straightforward. Instead of interacting with the TabCollection, use this class
/// instead.
/// </summary>
public class TabPageHelper
{
private List<TabPage> _allTabs;
private TabControl.TabPageCollection _tabCollection;
public Dictionary<string, int> TabOrder { get; private set; }
public TabPageHelper( TabControl.TabPageCollection tabCollection )
{
_allTabs = new List<TabPage>();
TabOrder = new Dictionary<string, int>();
foreach ( TabPage tab in tabCollection )
{
_allTabs.Add( tab );
}
_tabCollection = tabCollection;
foreach ( int index in Enumerable.Range( 0, tabCollection.Count ) )
{
var tab = tabCollection[index];
TabOrder[tab.Name] = index;
}
}
public void ShowTabPage( string tabText )
{
TabPage page = _allTabs
.Where( t => string.Equals( t.Text, tabText, StringComparison.CurrentCultureIgnoreCase ) )
.First();
int tabPageOrder = TabOrder[page.Name];
if ( !_tabCollection.Contains( page ) )
{
_tabCollection.Insert( tabPageOrder, page );
}
}
public void HideTabPage( string tabText )
{
TabPage page = _allTabs
.Where( t => string.Equals( t.Text, tabText, StringComparison.CurrentCultureIgnoreCase ) )
.First();
int tabPageOrder = TabOrder[page.Name];
if ( _tabCollection.Contains( page ) )
{
_tabCollection.Remove( page );
}
}
}
クラスを使用するには、タブコントロールのTabPagesプロパティを渡してコンポーネントを初期化した後、フォームロードメソッドでインスタンス化します。
public Form1()
{
InitializeComponent();
_tabHelper = new TabPageHelper( tabControl1.TabPages );
}
クラスは非表示/表示時にタブページの順序を記憶するため、すべてのタブページはアプリケーションの読み込み時に(つまり、デザインビューで)存在する必要があります。次のように、アプリケーション全体でそれらを選択的に非表示または表示できます。
_tabHelper.HideTabPage("Settings");
_tabHelper.ShowTabPage("Schedule");
タブページはいつでも非表示または表示できます。
'in VB
myTabControl.TabPages(9).Hide() 'to hide the tabpage that has index 9
myTabControl.TabPages(9).Show() 'to show the tabpage that has index 9
そして、Emile(およびSlugster)による答えに基づいて、(TabPagesの代わりに)TabControlを拡張する方が少し簡単であることがわかりました。このようにして、1回の呼び出しでページを非表示または表示に設定できます。また、非表示ページのnull参照を心配する必要もありません。
呼び出し例:MyTabControl.SetTabVisibilityExt( "tabTests"、isDeveloper);
public static class WinFormExtensions
{
public static TabPage FindTabByNameExt( this TabControl tc, string tabName)
{
foreach (TabPage tab in tc.TabPages)
if (tab.Name == tabName)
return tab;
return null;
}
private struct TabPageData
{
internal int Index;
internal TabControl Parent;
internal TabPage Page;
internal TabPageData(int index, TabControl parent, TabPage page)
{
Index = index;
Parent = parent;
Page = page;
}
internal static string GetKey(TabControl tc, TabPage tabPage)
{
string key = "";
if (tc == null || tabPage == null)
return key;
key = $"{tc.Name}:{tabPage.Name}";
return key;
}
internal static string GetKey(TabControl tc, string tabName)
{
string key = "";
if (tc == null)
return key;
key = $"{tc.Name}:{tabName}";
return key;
}
}
private static Dictionary<string, TabPageData> hiddenPages = new Dictionary<string, TabPageData>();
public static void SetTabVisibleExt(this TabControl tc, string tabName)
{
if (tc == null || tc.IsDisposed)
return;
if (tc.IsTabVisibleExt(tabName))
return;
string key = TabPageData.GetKey(tc, tabName);
if (hiddenPages.ContainsKey(key))
{
TabPageData tpinfo = hiddenPages[key];
if (tpinfo.Index < tc.TabPages.Count)
tc.TabPages.Insert(tpinfo.Index, tpinfo.Page); // add the page in the same position it had
else
tc.TabPages.Add(tpinfo.Page);
hiddenPages.Remove(key);
return;
}
else
throw new ApplicationException($"TabControl={tc.Name} does not have Invisible TabPage={tabName}");
}
public static void SetTabInvisibleExt(this TabControl tc, string tabName)
{
if (tc == null || tc.IsDisposed)
return;
if (IsTabInvisibleExt(tc, tabName))
return;
TabPage page = tc.FindTabByNameExt(tabName);
if (page != null)
{
string key = TabPageData.GetKey(tc, page);
TabPageData tpInfo = new TabPageData(tc.TabPages.IndexOf(page), tc, page);
tc.TabPages.Remove(page);
hiddenPages.Add(key, tpInfo);
return;
}
else // Could not find the tab, and it isn't already invisible.
throw new ApplicationException($"TabControl={tc.Name} could not locate TabPage={tabName}");
}
// A convenience method to combine the SetTabInvisible and SetTabInvisible.
public static void SetTabVisibilityExt(this TabControl tc, string tabName, bool? isVisible)
{
if (isVisible == null)
return;
if (isVisible.Value)
tc.SetTabVisibleExt(tabName);
else
tc.SetTabInvisibleExt(tabName);
}
public static bool IsTabVisibleExt(this TabControl tc, string tabName)
{
TabPage page = tc.FindTabByNameExt(tabName);
return page != null;
}
public static bool IsTabInvisibleExt(this TabControl tc, string tabName)
{
string key = TabPageData.GetKey(tc, tabName);
return hiddenPages.ContainsKey(key);
}
public static void CleanUpHiddenPagesExt(this TabControl tc)
{
foreach (TabPageData info in hiddenPages.Values)
{
if (info.Parent != null && info.Parent.Equals((TabControl)tc))
info.Page.Dispose();
}
}
}
Public Shared HiddenTabs As New List(Of TabPage)()
Public Shared Visibletabs As New List(Of TabPage)()
Public Shared Function ShowTab(tab_ As TabPage, show_tab As Boolean)
Select Case show_tab
Case True
If Visibletabs.Contains(tab_) = False Then Visibletabs.Add(tab_)
If HiddenTabs.Contains(tab_) = True Then HiddenTabs.Remove(tab_)
Case False
If HiddenTabs.Contains(tab_) = False Then HiddenTabs.Add(tab_)
If Visibletabs.Contains(tab_) = True Then Visibletabs.Remove(tab_)
End Select
For Each r In HiddenTabs
Try
Dim TC As TabControl = r.Parent
If TC.Contains(r) = True Then TC.TabPages.Remove(r)
Catch ex As Exception
End Try
Next
For Each a In Visibletabs
Try
Dim TC As TabControl = a.Parent
If TC.Contains(a) = False Then TC.TabPages.Add(a)
Catch ex As Exception
End Try
Next
End Function
非表示のTabPageをプライベートリストに保存するのと同じ方法を使用しましたが、問題は、TabPageを再度表示するときに、元の位置(順序)に表示されないことです。そこで、最後にVBでクラスを作成し、HideTabPageByNameとShowTabPageByNameの2つのメソッドでTabControlを追加します。TabPageインスタンスではなく、名前を渡すメソッドを呼び出すことができます。
Public Class CS_Control_TabControl
Inherits System.Windows.Forms.TabControl
Private mTabPagesHidden As New Dictionary(Of String, System.Windows.Forms.TabPage)
Private mTabPagesOrder As List(Of String)
Public Sub HideTabPageByName(ByVal TabPageName As String)
If mTabPagesOrder Is Nothing Then
' The first time the Hide method is called, save the original order of the TabPages
mTabPagesOrder = New List(Of String)
For Each TabPageCurrent As TabPage In Me.TabPages
mTabPagesOrder.Add(TabPageCurrent.Name)
Next
End If
If Me.TabPages.ContainsKey(TabPageName) Then
Dim TabPageToHide As TabPage
' Get the TabPage object
TabPageToHide = TabPages(TabPageName)
' Add the TabPage to the internal List
mTabPagesHidden.Add(TabPageName, TabPageToHide)
' Remove the TabPage from the TabPages collection of the TabControl
Me.TabPages.Remove(TabPageToHide)
End If
End Sub
Public Sub ShowTabPageByName(ByVal TabPageName As String)
If mTabPagesHidden.ContainsKey(TabPageName) Then
Dim TabPageToShow As TabPage
' Get the TabPage object
TabPageToShow = mTabPagesHidden(TabPageName)
' Add the TabPage to the TabPages collection of the TabControl
Me.TabPages.Insert(GetTabPageInsertionPoint(TabPageName), TabPageToShow)
' Remove the TabPage from the internal List
mTabPagesHidden.Remove(TabPageName)
End If
End Sub
Private Function GetTabPageInsertionPoint(ByVal TabPageName As String) As Integer
Dim TabPageIndex As Integer
Dim TabPageCurrent As TabPage
Dim TabNameIndex As Integer
Dim TabNameCurrent As String
For TabPageIndex = 0 To Me.TabPages.Count - 1
TabPageCurrent = Me.TabPages(TabPageIndex)
For TabNameIndex = TabPageIndex To mTabPagesOrder.Count - 1
TabNameCurrent = mTabPagesOrder(TabNameIndex)
If TabNameCurrent = TabPageCurrent.Name Then
Exit For
End If
If TabNameCurrent = TabPageName Then
Return TabPageIndex
End If
Next
Next
Return TabPageIndex
End Function
Protected Overrides Sub Finalize()
mTabPagesHidden = Nothing
mTabPagesOrder = Nothing
MyBase.Finalize()
End Sub
End Class