1

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.

edit:

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
Community
  • 1
  • 1
4ntibala
  • 137
  • 2
  • 3
  • 10
  • Converting this code to VB.NET would take a bit, could you please explain the exact problem you have more clearly? What you want to achieve and why you cannot do it with this code. – varocarbas Aug 05 '13 at 13:37
  • i edited my question.. hopefully its clearer now :) – 4ntibala Aug 05 '13 at 14:39
  • Way much clearer. It is a conversion/proper-understanding-original-C# problem, I hope that I have been clear in my answer. Next time, when a conversion is involved, better posting the converted code (usually the problem is there). – varocarbas Aug 05 '13 at 15:54

3 Answers3

1

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
varocarbas
  • 12,354
  • 4
  • 26
  • 37
  • hey.. thanks for the long reply :) but unfortunately, i have to say that indeed i do have all my tabpages in tabcontrols. it wasnt smart of me to copy and paste the edited version (including the function instead of the original sub) in my question's code.. anyhow.. i converted it back now as imho, after reading ur replies, it should be correct. but i am where i was before. tabpages do get hidden, bt never ever i can set them back to visible.. if u run my code ull see the little sub printallkeys() being called if **hiddenPages.ContainsKey(key)** is false.. so i can say for sure at least that – 4ntibala Aug 05 '13 at 20:19
  • @4ntibala Have you tried the simple test I proposed? If not, please do it: open a new project, include a tabControl and this code and your class as suggested and confirm that the Visible/Invisible code works fine. I wait for your input. – varocarbas Aug 05 '13 at 20:22
  • the problem is somewhere when writing a tabpage to the hidden list. the list, as printallkeys() shows, contains **tcManaging.tpEdit**.. but im calling the setvisible() sub from a class **frmMain.TM.SetVisible(frmMain.tcManaging.TabPages("tpEdit"), frmMain.tcManaging)**.. i suppose somewhere there is the 'real' problem?! – 4ntibala Aug 05 '13 at 20:23
  • @4ntibala OK. Let's do things step by step to understand each other without any problem and so being able to fix the problem :) – varocarbas Aug 05 '13 at 20:24
  • testing the scenario u described.. it works wonderful.. so basically my problem is that im calling from another form than frmMain ? #yes, with pleasure :) – 4ntibala Aug 05 '13 at 20:30
  • i guess the fact that im calling SetVisible() with parameters which include 'frmmain' at the beginning makes it not work. because in the hiddenpages_list the name of the tabpage+parentcontrol is written w/o the 'frmmain'... i tried using 'Me' keyword on frmmain, to make it equal.... but it doesn work – 4ntibala Aug 05 '13 at 20:34
  • @4ntibala your problem is what I said: your tabPages are not inside a tabControl or, at least, this is what your code thinks. If you test this sample, you would see that you are not able to find the TabPages inside the controls of the form (you can only find the TabControl), because they are not directly added to the form, but its parent (the tabControl). SetInvisible looks for the parent and in the simple case works because the tabPages have a parent; in your original case, the parent is nothing and this is most likely what provokes the problem. – varocarbas Aug 05 '13 at 20:34
  • @4ntibala There is no problem with the forms; the problem is the way in which you are adding the TabPages and the TabControl to your forms. Analyse this part and you would find the error. If you put a break point on Invisible with your original conditions, you would see that the parent is nothing and this is the problem. Now you have a code which works and thus the right path: analyse your code step by step (where the tabs are created/added mainly) and make sure that it emulates what the simple code does: take it easy and you will surely find the problem. – varocarbas Aug 05 '13 at 20:37
  • all my tabpages are residing in tabcontrols. all of them are added with the designer.. i never used the code with setinvisible() being a function.. just for testing purposes... i can say for 100% that my tabpages ARE in tabcontrols.. ill go thru it again.. but i am where i was when i created the question :D – 4ntibala Aug 05 '13 at 20:39
  • @4ntibala post the code where the tabs are added and perhaps I can see something (you know... 4 eyes see more than 2). What is clear is that you shouldn't be able to find the tabPages directly from the controls in the form, you can find there only the controls directly added, not the controls added to another control. – varocarbas Aug 05 '13 at 20:45
  • i edited again and posted all the code.. also my tabpages are created in design-mode... i really dont know anymore.. – 4ntibala Aug 05 '13 at 20:49
  • @4ntibala just to speed up things: wouldn't you mind to upload the whole solution such that I can take a really quick look at it and understand what is wrong here better? – varocarbas Aug 05 '13 at 20:54
  • not at all.. id love to.. thought that'd be against the rules or something... just let me zip it :) the function calls are the same as before.. thats it.. – 4ntibala Aug 05 '13 at 20:57
  • @4ntibala against what rules? At this point I am even more interested than you in knowing what is wrong here (now it is personal LOL). The important thing here is you to learn but when the situation evolves in such a way that there is no other solution... (letting it go or solving it are the only two options now) – varocarbas Aug 05 '13 at 20:59
  • @4ntibala if I open the project (with VS 2012) and run it in debug, it seems to work: if I press hide it hides, if i press show it shows... – varocarbas Aug 05 '13 at 21:09
  • @4ntibala it happens always to the first tab. This is the problem? (actually you have changed the code as I suggested). What is the exact problem now? – varocarbas Aug 05 '13 at 21:11
  • dont u see the 3rd button? there it goes into the clsMCQblaa.. and enters LoadEdit() where it tries to setvisible() no, i dont care which tab it is anymore.. :) and yes, of course i changed to ur code.. as i did when editing the question :P just had the boolean return function to see if something goes right there – 4ntibala Aug 05 '13 at 21:13
  • @4ntibala well... I show two big buttons show and hide and I thought that this was what you were looking for :) OK. Give me some minutes. – varocarbas Aug 05 '13 at 21:14
  • @4ntibala in the first line you do TabControl1.TabPages("tpEdit") that is you are looking for a tabPage called "tpEdit" inside TabControl1. But TabControl1 has just two TabPages TabPage1 and TabPage2 ?! Also bear in mind that you can access the tabs directly (as in my code): Form1.tpEdit. – varocarbas Aug 05 '13 at 21:17
  • yes, that line! and sorry, i forgot to change it.. but it is the same beahvoir.. jsut change it to tabpage1. it will not work! what do u mean by accesing them directly? are they in tabcontrols tho? would u mind talkin on pm somehwere? – 4ntibala Aug 05 '13 at 21:19
  • @4ntibala no problem. Sorry, the VS 2012 is giving me some problems (rarely using it). Will be back in brief. – varocarbas Aug 05 '13 at 21:23
  • in SetVisible() 'key' is always nothing when called from the class... sure.. take ur time. ill go mad meanwhile :D could as upload it as VS2010/2008 if u want.... – 4ntibala Aug 05 '13 at 21:24
  • @4ntibala the problem you have here is that are passing controls in the form wrongly (most likely you don't know how to use most of the tags you are writing (are just converted directly from C#)). Originally you have a problem, which I solved. What this code has is many more problems (+ the weird 2012 things which do not allow me to look at it properly). I will do this: I will create a new VS 2010 project to give you something to start with and then you will start doing things step by step. By letting completely clear that "this problem" is completely outside what you asked in your question.. – varocarbas Aug 05 '13 at 21:33
  • @4ntibala the "problem" you have is basically a messy code built from wrongly converting a working one (what is a horrible approach in general). I have spent pretty long time, I am tired and don't have other thing to do and will give you this small starting point, I hope that you will use it wisely to not be in this situation again where all are problems and you don't even know what most of the things are for. Write you back in a (short) while. – varocarbas Aug 05 '13 at 21:35
  • man u sound like i wrote delphi in there... :D the c# class is machine translated, i just made it compile without errors... but i guess there is the problem.. but thanks alot for going thru all this.. i appreciate :) – 4ntibala Aug 05 '13 at 21:45
  • @4ntibala ?!You don't need the new class! OK. Well, the code was certainly a mess, I had to rewrite to be able to run. But your original problem was what I said and is fixed, so please, award the question :) and next time have your ideas a bit clearer. – varocarbas Aug 05 '13 at 21:57
  • of course i will award it :) and i would greatly appreciate to actually see what was so wrong.. and yes, i DO need it.... just mentioned why it is so messy..i really dont understand the most of the tags used in there.. it was converted by a converter i just edited small things... to make it compile # u deserve it just for the trouble itself.. haha – 4ntibala Aug 05 '13 at 21:59
  • @4ntibala ?! but do you want the code or not? I thought that you knew already what was wrong! The code was a mess, I created various new parts but finally I said to myself "please... this has to be done by him!" so it is just a simple calling buttons. There you have it the simple project (VS 2010): http://www.mediafire.com/download/zr468e54e4a4e4z/WindowsApplication1.zip – varocarbas Aug 05 '13 at 22:03
  • @4ntibala everything was in place, the difficult thing was not making it run :) – varocarbas Aug 05 '13 at 22:04
  • at least it is written by somebody who actually knows c#... so must be better then my version.. ill take it as a start. maybe ill have some more questions :D THANK YOU :) – 4ntibala Aug 05 '13 at 22:05
  • @4ntibala no, I didn't touch the C# part. Just the calling part. Actually I created a way to select the tab to be shown but finally deleted it :) The kind of help you need is doing things by your own. – varocarbas Aug 05 '13 at 22:07
  • @4ntibala can I delete the .zip from the server? – varocarbas Aug 05 '13 at 22:10
  • u refered to the code in the clsMCQOps? argh lol... this was just to demonstrate the problem... 1 line. u didnt have to make it soo nice.. lol anyway... im soo soo glad its working now, thank you soo much! :) have a great day.. – 4ntibala Aug 05 '13 at 22:10
  • @4ntibala no problem. Nice?! (if you would see all the other parts I wrote... :)). Get the idea: everything was fine (except the first error I report), but if you keep putting things one on top of the other without even knowing what makes each thing you are getting crazy errors which wouldn't be there in case of doing things step by step. – varocarbas Aug 05 '13 at 22:13
  • what are u referring to? the clsTabManager? – 4ntibala Aug 05 '13 at 22:15
  • @4ntibala no. clsTabManager was converted from a working code and thus it was working (once you fixed the problem). I mean the system of classes and the way to pass the arguments... Instead creating a so messy structure which does not work, go step by step making sure that each bit works. As you can see in my code you have the basic classes but nothing else: it work, perfect. Now you can start to create a more intrincate system of classes, change the way in which the tagPages are inputted to the function, etc. Each time you change something, make sure that it works. Step by step and simpler. – varocarbas Aug 05 '13 at 22:18
  • yes.. it makes sense what u say. definately. :) but right now im thinking if VS2012 maybe messed up "my" code? because if i look at the project i sent u it contains exactly 5 lines of code that actually do something o.O if u refer to the few lines i commented out... yes.. i should have deleted them... but i dont think u mean them.. – 4ntibala Aug 05 '13 at 22:25
  • @4ntibala I wouldn't say that it was 2012. Bear in mind that I created the project from scratch; yours was modified many times. What I saw when dealing with your code was the result from a messy development: it was acting crazy. Best thing in these situations is start a project from scratch. Logically 2010 is more stable than 2012 but I am pretty sure that the weird behaviour was provoked by you, not by VS 2012 :) – varocarbas Aug 05 '13 at 22:29
1

I just implemented your suggested code and came up with a problem. It centers around trying to make a previously invisible tab page visible again. The problem is that once a tab page is made invisible, it no longer is part of the tab control. It is stored inside one of the TabpageData structures so it can later be retrieved. But, in order to make the tab page visible again, I had to modify the SetVisible() method to include the PageName and not the Tabpage, as well as the GetKey() function to pass in the tabcontrol and the tab's name.

Here's the new GetKey():

Friend Shared Function GetKey ( tabCtrl As TabControl, tabName As string ) As String
    Dim key As String = ""

    If tabCtrl IsNot Nothing  Then
        key = [String].Format( "{0}:{1}", tabCtrl.Name, tabName )
    End If
    Return key
End Function

And here is the new SetVisible:

Public Sub SetVisible ( PageName As String, parent As TabControl )
    If parent IsNot Nothing AndAlso Not parent.IsDisposed Then
        Dim tpinfo As TabPageData
        Dim key    As String = TabPageData.GetKey ( parent, PageName )

        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
Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
0

You need to check for if a postback or not in your frmMain_Load so that it doesn't always set invisible.

Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load

If Not Page.IsPostBack Then
    clsTabManager.SetInvisible(tcManaging.TabPages("tpEdit"))
End If

End Sub
Jim
  • 624
  • 8
  • 20