web-dev-qa-db-fra.com

Masquer et afficher des pages de tabulation dans tabControl

J'essaie d'afficher ou de masquer les pages de tabulation selon le choix de l'utilisateur. Si l'utilisateur sélectionne le sexe masculin, le formulaire pour homme dans une page d'onglet "homme" doit être affiché. S'il sélectionne une femme, le formulaire suivant doit s'afficher dans l'onglet suivant "femme"

J'ai essayé d'utiliser

tabControl1.TabPages.Remove(...)

et 

tabControl1.TabPages.Add(...)

Il ajoute et supprime les pages de tabulation, mais mes contrôles seront également perdus ... je ne peux pas les voir. quel est le problème ici?

29
KoolKabin

Vous pouvez supprimer la page à onglet de la collection TabControl.TabPages et la stocker dans une liste. Par exemple:

    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);
    }
31
Hans Passant

Je pense que la réponse est beaucoup plus facile.

Pour masquer l'onglet, vous pouvez simplement utiliser la façon dont vous avez déjà essayé ou en adressant la page de tabulation elle-même.

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

a.s.o.

Supprimer TabPage ne le détruit pas, pas plus que ses contrôles . Pour afficher à nouveau l'onglet correspondant, utilisez simplement le code suivant

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

Pour améliorer la bonne solution de Hans Passant, j'ai décidé d'écrire une méthode d'extension basée sur sa solution et d'ajouter d'autres éléments. Je suis surpris que, même dans .NET 4, cette fonctionnalité de base n'ait pas été corrigée.

  • Implémenté comme une méthode d'extension pouvant être réutilisée de manière plus transparente
  • La méthode de nettoyage nettoie que les pages du contrôle en cours d’élimination/nettoyage.
  • Dans la mesure du possible, la page à onglet est restaurée à la même position. Ce n'est pas toujours possible si vous masquez/affichez plusieurs pages à onglet.
  • Il fait quelques erreurs et vérification des paramètres
  • Pour le rendre invisible, il découvre son parent. Lorsqu’il est visible, il doit être indiqué Car la propriété Parent a la valeur null lorsque la page à onglet a été supprimée.


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

    }
6
Emile

Une approche différente consisterait à avoir deux contrôles d’onglet, l’un visible, l’autre non. Vous pouvez déplacer les onglets de l’un à l’autre comme ceci (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

Si l'ordre des tabulations est important, remplacez la méthode .Add de tabsShown par .Insert et spécifiez la position ordinale. Une façon de faire est d'appeler une routine qui renvoie la position ordinale souhaitée.

2
Mmm

J'ai un exemple de code qui fonctionne mais je veux le rendre un peu mieux en référençant l'onglet de la liste:

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
1
KoolKabin
    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);
                }
            }
        };
    }

Utilisé comme ceci:

    var showOnly = this.TabContainer1.GetTabHider();
    showOnly((tab) => tab.Text != "tabPage1");

L'ordre d'origine est conservé en conservant une référence à l'instance de fonction anonyme. 

1
Rob

Je préfère faire l'apparence de style à plat: https://stackoverflow.com/a/25192153/5660876

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

Mais il y a un pixel qui est affiché à chaque page de tabulation, donc si vous supprimez tout le texte de chaque page de tabulation, les onglets deviennent alors parfaitement invisibles à l'exécution. 

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

Après cela, j'utilise un arbre, pour changer de page de tabulation ... en cliquant sur les nœuds.

1
GeMe

Il me semble plus facile d'effacer tous les TabPages et d'ajouter ceux souhaités:

PropertyTabControl.TabPages.Clear();
        PropertyTabControl.TabPages.Add(AspectTabPage);
        PropertyTabControl.TabPages.Add(WerkstattTabPage);

ou 

PropertyTabControl.TabPages.Clear();
        PropertyTabControl.TabPages.Add(TerminTabPage);
1
staecker

Si vous pouvez vous permettre d'utiliser l'élément Tag de la TabPage, vous pouvez utiliser cette méthode d'extension

    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);
        }
    }
0
Pockets

vous pouvez toujours masquer ou afficher la page à onglet.

'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
0
Paulo Lima

Et en me basant sur la réponse d’Emile (et de Slugster), j’ai trouvé un peu plus facile d’étendre le TabControl (au lieu des TabPages). De cette manière, je peux définir des pages invisibles ou visibles avec un seul appel, sans avoir à me soucier des références parent nuls pour les pages invisibles.

Exemple d'appel: 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();
        }
    }

}
0
batpox
    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
0
Mattheu Norwood

J'utilise la même approche pour enregistrer les TabPages masqués dans une liste privée, mais le problème est que, lorsque je souhaite afficher à nouveau TabPage, ils n'apparaissent pas à la position (ordre) d'origine. Donc, finalement, j’ai écrit une classe dans VB pour ajouter le TabControl avec deux méthodes: HideTabPageByName et ShowTabPageByName. Vous pouvez simplement appeler les méthodes en passant le nom (pas l'instance de 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
0
Tomas A. Cardoner