在tabControl中隐藏和显示选项卡页

46

我想根据用户的选择显示或隐藏选项卡。如果用户选择了男性,则应在名为“男性”的选项卡页面上显示男性表单,如果用户选择了女性,则应在下一个选项卡“女性”中显示类似的下一个表单。

我尝试使用以下代码:

tabControl1.TabPages.Remove(...)
并且
tabControl1.TabPages.Add(...)

它添加和删除选项卡页,但这样做会丢失我在选项卡页上的控件...我无法再看到它们。这里问题出在哪里?


1
选项卡页面的“可见性属性”无效吗? - sukru
4
已验证:选项卡页实际上并没有公开 Visible 属性。 - Paul Sasik
1
而且Show和Hide方法也不是... - Justin Ethier
要隐藏所有选项卡,请使用tabControl1.Visible = false; - Martin
21个回答

49

我认为答案要简单得多。

要隐藏选项卡,您可以使用您已经尝试过的方法或直接针对TabPage本身进行操作。

TabControl1.TabPages.Remove(TabPage1) 'Could be male
TabControl1.TabPages.Remove(TabPage2) 'Could be female

a.s.o.

移除选项卡页并不会销毁它和其上的控件。

要再次显示相应的选项卡,只需使用以下代码:

TabControl1.TabPages.Insert(0, TabPage1) 'Show male
TabControl1.TabPages.Insert(1, TabPage2) 'Show female

41

您可以从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);
    }

我发现添加选项卡页很困难...你能发一些完整的例子吗?我理解了你的方法,但在添加时想知道如何引用选项卡,因为它之前已被删除。 - KoolKabin
只需向您的类添加一个成员即可。Windows Forms设计器已经完成了这项工作,例如“tabPage1”。 - Hans Passant
我想引用TabPage1,我需要写me.TabPages("tabPage1")吗? - KoolKabin
不,只需使用 tabPage1。它是表单类的一个成员。 - Hans Passant
嗨,它甚至在没有hiddenpages变量的情况下也能工作...那么它有什么特殊用途吗? - KoolKabin
是的,在表单关闭时处理隐藏页面很重要。 - Hans Passant

7

在Hans Passant的好解决方案的基础上,我决定编写一个扩展方法,并添加其他东西。令人惊讶的是,即使在.NET 4中,这种基本功能仍未被修复。

  • 将其实现为扩展方法,可以以更透明的方式重用
  • 清理方法仅清理正在被处理/清理的控件的页面。
  • 尽可能恢复选项卡页到其相同的位置。如果隐藏/显示了几个选项卡页,则不总是可能。
  • 它进行了一些错误和参数检查
  • 为了使其不可见,它找到了它的父级。当使其可见时,必须给出此属性,因为当选项卡页被移除时,Parent属性为空。


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();
            }
        }

    }

非常好用 - 非常感谢。由于Stackoverflow正在破坏您代码的开头和结尾,您可能需要提交一个错误报告。 - Dan W
哦,当有太多的选项卡时,我该如何隐藏箭头以避免对用户造成干扰? - Dan W

6

我倾向于使用扁平化的外观样式: https://dev59.com/q3RB5IYBdhLWcg3wr44U#25192153

    tabControl1.Appearance = TabAppearance.FlatButtons;
    tabControl1.ItemSize = new Size(0, 1);
    tabControl1.SizeMode = TabSizeMode.Fixed;

但是每个选项卡都显示一个像素,因此如果您删除每个选项卡的所有文本,则选项卡在运行时完全不可见。

    foreach (TabPage tab in tabControl1.TabPages)
    {
        tab.Text = "";
    }

之后我使用了一个树形视图,通过点击节点来切换选项卡页面。


1
这是最优雅的解决方案。起初,我认为它无法避免用户使用键盘上的Tab键切换到TabControl,然后使用上下左右箭头键导航到一个即使被隐藏的选项卡。但是我已经测试过了,并且可以确认此解决方案可以防止用户使用Tab键和箭头键绕过它。您可以使用以下代码在选项卡之间进行编程切换:TabControl1.SelectedTab = TabPage1 - TurnerOC
2
哦,还要设置TabStop=false。 - TurnerOC

4

另一种方法是使用两个选项卡控件,一个可见,一个不可见。您可以像这样将选项卡从一个控件移动到另一个控件(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,并指定序号位置。一种实现方式是调用一个返回所需序号位置的程序。


在我的情况下,RemoveByKey 能够正常工作,而 Remove 则不能。唯一可能解释这种情况的是,我尝试删除嵌套的 TabPages。 - JRB

2

您可以随时隐藏或显示选项卡页面。

'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

1
    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");

通过保留对匿名函数实例的引用,可以保留原始排序。


1

有人将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");

1

添加和删除选项卡可能会有点不太有效

也许这会有所帮助

隐藏/显示选项卡页面 => 让tabControl1的tabPage1

tapPage1.Parent = null;            //to hide tabPage1 from tabControl1
tabPage1.Parent = tabControl1;     //to show the tabPage1 in tabControl1

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接