I try to hide and show tabpages dynamically at runtime. For this I converted the code of Emile from here to vb.net and the resulted problem is that tabpages cannot be shown anymore after they were hidden. At least not if they were set to invisible somewhere else than where I am trying set them visible.
After a long discussion i finally came up with a working result. i corrected the calling procedures and now this code works. It can hide and show tabpages that reside on any form, just like the original version does. Thanks go to user varocarbas..
Hiding a tabpage:
clsTabManager.SetInvisible(tabPage)
Showing a tabpage (call from any class/form):
clsTabManager.SetVisible(FormWithTabControl.tabPage, FormWithTabControl.TabControl)
Showing a tabpage (call from Form where TabControl resides):
clsTabManager.SetVisible(tabPage, TabControl)
clsTabmanager:
Public Class clsTabManager
Private Structure TabPageData
Friend Index As Integer
Friend Parent As TabControl
Friend Page As TabPage
Friend Sub New(index__1 As Integer, parent__2 As TabControl, page__3 As TabPage)
Index = index__1
Parent = parent__2
Page = page__3
End Sub
Friend Shared Function GetKey(tabCtrl As TabControl, tabPage As TabPage) As String
Dim key As String = ""
If tabCtrl IsNot Nothing AndAlso tabPage IsNot Nothing Then
key = [String].Format("{0}:{1}", tabCtrl.Name, tabPage.Name)
End If
Return key
End Function
End Structure
Private hiddenPages As New Dictionary(Of String, TabPageData)()
Public Sub SetVisible(page As TabPage, parent As TabControl)
If parent IsNot Nothing AndAlso Not parent.IsDisposed Then
Dim tpinfo As TabPageData
Dim key As String = TabPageData.GetKey(parent, page)
If hiddenPages.ContainsKey(key) Then
tpinfo = hiddenPages(key)
If tpinfo.Index < parent.TabPages.Count Then
parent.TabPages.Insert(tpinfo.Index, tpinfo.Page)
Else
' add the page in the same position it had
parent.TabPages.Add(tpinfo.Page)
End If
hiddenPages.Remove(key)
End If
End If
End Sub
Public Sub SetInvisible(page As TabPage)
If IsVisible(page) Then
Dim tabCtrl As TabControl = DirectCast(page.Parent, TabControl)
Dim tpinfo As TabPageData
tpinfo = New TabPageData(tabCtrl.TabPages.IndexOf(page), tabCtrl, page)
tabCtrl.TabPages.Remove(page)
hiddenPages.Add(TabPageData.GetKey(tabCtrl, page), tpinfo)
End If
End Sub
Public Function IsVisible(page As TabPage) As Boolean
Return page IsNot Nothing AndAlso page.Parent IsNot Nothing
' when Parent is null the tab page does not belong to any container
End Function
Public Sub CleanUpHiddenPage(page As TabPage)
For Each info As TabPageData In hiddenPages.Values
If info.Parent IsNot Nothing AndAlso info.Parent.Equals(DirectCast(page.Parent, TabControl)) Then
info.Page.Dispose()
End If
Next
End Sub
Public Sub CleanUpAllHiddenPages()
For Each info As TabPageData In hiddenPages.Values
info.Page.Dispose()
Next
End Sub
End Class
The conversion you have done of the original C# code is not perfect (you should understand what each part does, instead of copying bit by bit). In the SetVisible
/SetInvisible
part this is the problem:
Public Shared Function SetInvisible(page As TabPage, frm As Form) 'As Boolean
page = frm.Controls(page.Name)
If IsVisible(page) Then
Dim tabCtrl As TabControl = DirectCast(page.Parent, TabControl)
Dim tpinfo As TabPageData
tpinfo = New TabPageData(tabCtrl.TabPages.IndexOf(page), tabCtrl, page)
tabCtrl.TabPages.Remove(page)
hiddenPages.Add(TabPageData.GetKey(tabCtrl, page), tpinfo)
End If
End Function
(this should be a Sub
rather than a Function
) You are adding a bit not present in the original code: page = frm.Controls(page.Name)
; I guess that it is an adaptation to make the code work under your specific conditions (you have added to the form a TabPage
alone, instead one inside a TabControl
, what is the normal behaviour). This would be fine, but you are not adapting the SetVisible function to this reality:
Public Shared Sub SetVisible(page As TabPage, parent As TabControl)
If parent IsNot Nothing AndAlso Not parent.IsDisposed Then
Dim tpinfo As TabPageData
Dim key As String = TabPageData.GetKey(parent, page)
If hiddenPages.ContainsKey(key) Then
tpinfo = hiddenPages(key)
If tpinfo.Index < parent.TabPages.Count Then
parent.TabPages.Insert(tpinfo.Index, tpinfo.Page)
Else
' add the page in the same position it had
parent.TabPages.Add(tpinfo.Page)
End If
hiddenPages.Remove(key)
Else
PrintAllKeys()
End If
End If
End Sub
Understand what both functions do: the first one (modified by you) expects a TabPage added to the form directly (thus with no parent TabControl); the second one (as in the original C# code) expects a TabPage with a parent TabControl but your input does not have that. How I know that? If your TabPage would have a TabControl as a parent, the page = frm.Controls(page.Name)
would be Nothing
.
If you want to use this code you have to provide the expected inputs, that is, TabPages inside a TabControl. Otherwise, you should modify it accordingly (not just one part, all the parts). Easy test for you to understand what is required:
1- Open a new project and add a new TabControl via "Design View".
2- Copy your class but let SetInvisible as in the original version (delete page = frm.Controls(page.Name)
).
3- Test your class with the main form and see that it works fine. Sample code (these are the default names when you add a new TabControl
):
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Dim test As clsTabManager = New clsTabManager()
test.SetInvisible(TabPage1, Me)
test.SetVisible(TabPage1, TabControl1)
End Sub