Hiding and Showing TabPages in tabControl
I am trying to show or hide tabpages as per user choice. If user selects gender male then form for male in a tabpage "male" should be displayed and if user selects female then similar next form should be displayed in next tab "female"
I tried using
tabControl1.TabPages.Remove(...)
and
tabControl1.TabPages.Add(...)
It adds and re开发者_如何学JAVAmoves the tabpages but doing so will loose my controls on tabpages too... i can't see them back. what's the problem here?
I think the answer is much easier.
To hide the tab you just can use the way you already tried or adressing the TabPage itself.
TabControl1.TabPages.Remove(TabPage1) 'Could be male
TabControl1.TabPages.Remove(TabPage2) 'Could be female
a.s.o.
Removing the TabPage does not destroy it and the controls on it. To show the corresponding tab again just use the following code
TabControl1.TabPages.Insert(0, TabPage1) 'Show male
TabControl1.TabPages.Insert(1, TabPage2) 'Show female
You could remove the tab page from the TabControl.TabPages collection and store it in a list. For example:
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);
}
Improving on the good solution by Hans Passant I decided to write an extension method based on his solution and adding other stuff as well. I am surprised that even in .NET 4 this basic functionality hasn't been fixed.
- Implemented it as an Extension Method that can be reused in a more transparent manner
- The clean up method only cleans up the pages of the control being disposed/cleaned up.
- Whenever possible the tab page is restored to its same position. This isn't always possible if you hide/show several tab pages.
- It does some error and parameter checking
- To make it invisible it finds out its parent. When making visible it has to be given because the Parent property is null when the tab page has been removed.
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();
}
}
}
A different approach would be to have two tab controls, one visible, and one not. You can move the tabs from one to the other like this (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
If the tab order is important, change the .Add method on tabsShown to .Insert and specify the ordinal position. One way to do that is to call a routine that returns the desired ordinal position.
I prefer to make the flat style appearance: https://stackoverflow.com/a/25192153/5660876
tabControl1.Appearance = TabAppearance.FlatButtons;
tabControl1.ItemSize = new Size(0, 1);
tabControl1.SizeMode = TabSizeMode.Fixed;
But there is a pixel that is shown at every tabPage, so if you delete all the text of every tabpage, then the tabs become invisible perfectly at run-time.
foreach (TabPage tab in tabControl1.TabPages)
{
tab.Text = "";
}
After that i use a treeview, to change through the tabpages... clicking on the nodes.
you can always hide or show the tabpage.
'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
I have my sample code working but want to make it somewhat more better refrencing the tab from list:
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);
}
}
};
}
Used like this:
var showOnly = this.TabContainer1.GetTabHider();
showOnly((tab) => tab.Text != "tabPage1");
Original ordering is retained by retaining a reference to the anonymous function instance.
It looks easier for me to clear all TabPages add add those wished:
PropertyTabControl.TabPages.Clear();
PropertyTabControl.TabPages.Add(AspectTabPage);
PropertyTabControl.TabPages.Add(WerkstattTabPage);
or
PropertyTabControl.TabPages.Clear();
PropertyTabControl.TabPages.Add(TerminTabPage);
Someone merged the C# answer into this one so I have to post my answer here. I didn't love the other solutions so I made a helper class that will make it easier to hide / show your tabs while retaining the order of tabs.
/// <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 );
}
}
}
To use the class, instantiate it in your form load method after initializing your components by passing in the tab control's TabPages property.
public Form1()
{
InitializeComponent();
_tabHelper = new TabPageHelper( tabControl1.TabPages );
}
All of your tab pages should exist on application load (ie: in the Design view) because the class will remember the order of the tab pages when hiding / showing. You can hide or show them selectively throughout your application like this:
_tabHelper.HideTabPage("Settings");
_tabHelper.ShowTabPage("Schedule");
I've been using the same approach of saving the hidden TabPages in a private list, but the problem is that when I want to show the TabPage again, they doesn't appears in the original position (order). So, finally, I wrote a class in VB to add the TabControl with two methods: HideTabPageByName and ShowTabPageByName. You can just call the methods passing the name (not the TabPage instance).
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
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
And building upon the answer by Emile (and Slugster), I found it a bit easier to extend the TabControl (instead of the TabPages). In this way I can set pages invisible or visible with a single call, and also not have to worry about the null parent references for the invisible pages.
Example call: 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();
}
}
}
If you can afford to use the Tag
element of the TabPage
, you can use this extension methods
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);
}
}
Adding and removing tab may be a bit less effective May be this will help
To hide/show tab page => let tabPage1 of tabControl1
tapPage1.Parent = null; //to hide tabPage1 from tabControl1
tabPage1.Parent = tabControl1; //to show the tabPage1 in tabControl1
There are at least two ways to code a solution in software... Thanks for posting answers. Just wanted to update this with another version. A TabPage array is used to shadow the Tab Control. During the Load event, the TabPages in the TabControl are copied to the shadow array. Later, this shadow array is used as the source to copy the TabPages into the TabControl...and in the desired presentation order.
Private tabControl1tabPageShadow() As TabPage = Nothing
Private Sub Form2_DailyReportPackageViewer_Load(sender As Object, e As EventArgs) Handles Me.Load
LoadTabPageShadow()
End Sub
Private Sub LoadTabPageShadow()
ReDim tabControl1tabPageShadow(TabControl1.TabPages.Count - 1)
For Each tabPage In TabControl1.TabPages
tabControl1tabPageShadow(tabPage.TabIndex) = tabPage
Next
End Sub
Private Sub ViewAllReports(sender As Object, e As EventArgs) Handles Button8.Click
TabControl1.TabPages.Clear()
For Each tabPage In tabControl1tabPageShadow
TabControl1.TabPages.Add(tabPage)
Next
End Sub
Private Sub ViewOperationsReports(sender As Object, e As EventArgs) Handles Button10.Click
TabControl1.TabPages.Clear()
For tabCount As Integer = 0 To 9
For Each tabPage In tabControl1tabPageShadow
Select Case tabPage.Text
Case "Overview"
If tabCount = 0 Then TabControl1.TabPages.Add(tabPage)
Case "Production Days Under 110%"
If tabCount = 1 Then TabControl1.TabPages.Add(tabPage)
Case "Screening Status"
If tabCount = 2 Then TabControl1.TabPages.Add(tabPage)
Case "Rework Status"
If tabCount = 3 Then TabControl1.TabPages.Add(tabPage)
Case "Secondary by Machine"
If tabCount = 4 Then TabControl1.TabPages.Add(tabPage)
Case "Secondary Set Ups"
If tabCount = 5 Then TabControl1.TabPages.Add(tabPage)
Case "Secondary Run Times"
If tabCount = 6 Then TabControl1.TabPages.Add(tabPage)
Case "Primary Set Ups"
If tabCount = 7 Then TabControl1.TabPages.Add(tabPage)
Case "Variance"
If tabCount = 8 Then TabControl1.TabPages.Add(tabPage)
Case "Schedule Changes"
If tabCount = 9 Then TabControl1.TabPages.Add(tabPage)
End Select
Next
Next
Always codes should be simple and easy to perform tasks for fast performance and for good reliability.
To add a page to a TabControl, the following code is enough.
If Tabcontrol1.Controls.Contains(TabPage1) Then
else
Tabcontrol1.Controls.Add(TabPage1)
End If
To remove a page from a TabControl, the following code is enough.
If Tabcontrol1.Controls.Contains(TabPage1) Then Tabcontrol1.Controls.Remove(TabPage1) End If
I wish to thank Stackoverflow.com for providing sincere help to programmers.
TabPanel1.Visible = true; // Show Tabpage 1
TabPanel1.Visible = false; //Hide Tabpage 1
First copy the tab into a variable then use insert to bring it back.
TabPage tpresult = tabControl1.TabPages[0];
tabControl1.TabPages.RemoveAt(0);
tabControl1.TabPages.Insert(0, tpresult);
You Can Use the Following
tabcontainer.tabs(1).visible=true
1 is tabindex
精彩评论