Results 1 to 12 of 12

Thread: VB.NET - Migrating from single Form to Tab Control

  1. #1

    Thread Starter
    Member
    Join Date
    Jun 2013
    Posts
    50

    VB.NET - Migrating from single Form to Tab Control

    I have a simple visibility board application that shows the status of activity in a department on a simple Form. The information is updated from a database and has been working fine. Now I would like the ability to show status from a couple different locations, and was thinking of migrating this to a Tab Control with two tabs. I added a form with the tab control and migrated the existing controls from the form to one of the tabs. I'm having difficulty accessing the controls on the tab pages.

    In the original app, I used the following code to update the control pbLight1 :

    DirectCast(Me.Controls("pbLight" & vBay), PictureBox).Image = My.Resources.Green

    In the above code, the vBay was a variable that indicated which Bay would be updated. The program provided visibility to bays 1 through 7. The same code no longer works when the controls are placed in the Tab Control pages. Logic is not an issue as the program had been working correctly.

    I'd appreciate input regarding the proper syntax needed to reference the controls such as pbLight1, etc now that they are on the TabControl.

  2. #2
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: VB.NET - Migrating from single Form to Tab Control

    In the original code, the Bay (I assume it's a PictureBox) was directly on the form. So when you said "Me.Controls", it worked.

    The Controls collection is not recursive. So when you moved it into a TabControl, it's no longer in the Form's Controls property: it's part of the TabControl's properties and, more specifically, it belongs to the TabPage.

    In my opinion, the best way to handle this with the smallest amount of code is to make an array at form load:
    Code:
    Private _bays As PictureBox()
    
    Sub FormWhatever_Load(...) Handles Blah blah
      _bays = New PictureBox() { _pbLight1, _pbLight2, ..., pbLight7 }
    End Sub
    That way, it doesn't matter who "owns" each picture box, you can get to them directly.

    A more advanced way would be to make derived TabPages with properties to represent the controls you want to access, but you'd have to do a bit more coding to get there.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  3. #3

    Thread Starter
    Member
    Join Date
    Jun 2013
    Posts
    50

    Re: VB.NET - Migrating from single Form to Tab Control

    Okay - I haven't worked with Arrays so that would take some research. I suppose a different question is how to refer to controls using a variable? For example, in the original program, I could update the pbLight1 using the DirectCast statement and the variable vBay; where vBay held the value of the bay being updated at the time. Is there a different way to update the control than us direct name?

  4. #4
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: VB.NET - Migrating from single Form to Tab Control

    Arrays are a fundamental aspect of using VB, you most definitely need to spend some time playing with them. Surging forward with a project before learning the fundamentals is a good way to fall on your face a lot and get frustrated. A lot of people don't like hearing that. Imagine I told you, "Well, I haven't learned multiplication yet, but I really want to take Calculus, I'm sure I can learn it as I go!" You'd probably think I was silly!

    The reason your previous code worked had nothing to do with DirectCast. Your code is doing several things on one line. If we wrote it out the "hard" way, it would look like this:
    Code:
    Dim controlName As String = "pbLight" & vBay
    Dim unconvertedControl As Control = Me.Controls(controlName)
    Dim picBox As PictureBox = DirectCast(unconvertedControl, PictureBox)
    picBox.Image = My.Resources.Green
    DirectCast() just tells the compiler to try and treat a variable of one type as if it were a variable of another type. If you don't have a value for that variable yet, it doesn't do much. So your problem is you want to use a string to refer to a control, or perhaps some other variable, because you can't hard-code the name you want to use.

    The reason the old code worked is because the control was inside the Form's Controls property. Now you've moved the controls around, and none of them are in the same parent's Controls property.

    The easiest solution to this problem is to use an array. A slightly fancier solution would use a Dictionary(Of String, PictureBox) so you could use string names, but since you are using numbers an array is simpler.

    You can write code that recursively iterates through every control's Controls property to see if it can find a child with the indicated name. But you'll have to modify the standard tutorials, because I'm not sure if the pages show up in TabControl.Controls as well as TabControl.TabPages. It's more complicated, a much harder concept to learn, and sort of like using a chainsaw to cut your hair.

    The only other non-array solution to this problem will be tedious: you'll have to write and maintain a lookup function yourself:
    Code:
    Function GetBayLight(ByVal index As Integer) As PictureBox
      If index = 1 Then
        Return pbLight1
      Else If index = 2 Then
        Return pbLight2
      ...
    It would be much easier to find a few tutorials about arrays, write a quick program to test your knowledge, then use them. Here is a very quick primer.

    Normal variables are like custom fit boxes for the things they hold. An Integer variable holds 1 integer. If you put another Integer in it, the old one's destroyed. This is true for all variables you've used so far.

    Array variables are more like boxes for the boxes that you put things in. That is, they hold more than one item. An egg carton is like an array for 12 eggs. You can swap out egg #3 with a new one, but that doesn't mean you swapped out the carton. The same is true of an array of Integer: it represents some number of integers with one variable name.

    You declare array variables by putting a () after their name:
    Code:
    Dim ints() As Integer
    Public carton() As Egg
    
    Sub Sort(ByVal cards() As Card)
    Those are prounounced, in order:
    • An Integer array variable named "ints".
    • An Egg array variable named "carton".
    • A Sub that takes a Card array parameter named "cards".


    When you declare an array that way, it's not ready yet. It needs to know its size. If you don't specify a size, the array is Nothing, much like how if you don't use New many variables are Nothing. You declare the size by putting the number that represents the highest index you want in the parenthesis:
    Code:
    Dim ints(10) As Integer
    Dim carton(11) As Egg
    Pay attention to that size. I said "The highest index you want", not "the number of values". Numbering of array elements starts at 0, so the variables above are:
    • An Integer array variable named "ints" with 11 elements, 0-10.
    • An Egg array variable named "carton" with 12 elements, 0-11.

    Most people mess this up and end up using the size they want. These people mistook VB .NET for an easy programming language that makes sound choices to help you succeed. VB is a language that makes many choices for you that require memorizing something that goes against common sense. This is the first of many things you will have to memorize if you want to succeed with VB.

    Once you have your array, you access its elements by using parenthesis and a number. For example, this code makes "an integer array named numbers with three elements: 1, 2, and 3:
    Code:
    Dim numbers(2) As Integer
    numbers(0) = 1
    numbers(1) = 2
    numbers(2) = 3
    You can also get the value of array elements using that syntax. Treat them like you would a variable:
    Code:
    Dim sum As Integer = numbers(0) + numbers(1) + numbers(2)
    For loops and arrays get along nicely, but that's another lesson. Suppose you have a set of things you want to set the array to, like my numbers array. There is a shortcut to creating arrays that lets you type out the elements in advance, rather than having to set them one per line:
    Code:
    Dim greetings() As String = { "Hello!", "Hi!", "Howdy!", "*grunt*" }
    That is an array of String named "greetings" with 4 elements. The curly brackets indicate the start and end of the array. I'm not sure why Microsoft didn't decide to be cute and use "Start Array" and "End Array" for that, it's scientifically proven 95% of VB .NET users die immediately if they see a curly bracket. Anyway.

    Whoa though, I didn't give it a size, did I? It turns out, if you're going to tell the array what elements it should have, you don't have to give it a size. Those curly brackets basically ARE an array, so the compiler can tell the right size is "3" for a 4-element array. You can give it a size, but if you make a mistake you'll have to fix it, so why bother?

    Arrays generally cannot be resized. There is a ReDim statement that can be used to resize them, and it comes in a ReDim Preserve form that also keeps the same elements. What's that mean? Well:
    Code:
    Dim numbers() As Integer = { 1, 2, 3 }
    ReDim numbers(8)
    When this is finished, numbers() will be "An Integer array variable with 9 elements." The values will be { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, because ReDim creates a new array and does not keep the values. Now consider this code:
    Code:
    Dim forms() As Form = { New Form1(), New Form2() }
    ReDim Preserve forms(2)
    After this code runs, forms is "A Form array with 3 elements." The values are { <some Form1>, <some Form2>, Nothing }. See how ReDim Preserve kept the old values, and only added the new values?

    You can also use ReDim/ReDim Preserve to make arrays smaller.

    When resizing arrays, keep in mind this isn't efficient. To make a new array, VB has to allocate all the memory, then (if Preserve is used) copy the old values into the new array. For really big arrays, this is really slow. Try to avoid resizing arrays. There is a class called List(Of T) that is better at being a resizable array, but for now we are talking about arrays.

    That's basically all there is to know, outside of some nuances of reference-type variables that would distract. Write some code with some arrays, and get a feel for how they work. Search the internet and these forums for "VB .NET control array" and you'll find hundreds of articles, some of them even worth your time to read. Don't spend another day afraid of arrays, a developer without arrays is sort of like a carpenter without a hammer.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  5. #5

    Thread Starter
    Member
    Join Date
    Jun 2013
    Posts
    50

    Re: VB.NET - Migrating from single Form to Tab Control

    I do understand Arrays from prior programming, but don't see how they will help me update the control.

    Let me provide more background. The Controls are used to display status for our service bays. The scope of the Visibility Board will be expanded to included more bays. Information about each bay is stored and updated real time in a SQL Server Database. Updates are made every few seconds to provide updates to the visibility board. Below is the original code that updates the pbLight controls:

    vActiveUpdate = True

    If Me.Controls("lblTot" & vBay).Text > 0 Then
    timespan = Now().Subtract(DirectCast(Me.Controls("dtTime" & vBay), DateTimePicker).Value)
    vMin = (timespan.Days * 1440) + (timespan.Hours * 60) + (timespan.Minutes)
    Me.Controls("lblRemain" & vBay).Text = Me.Controls("lblTot" & vBay).Text - vMin
    vPrcntRemain = Me.Controls("lblRemain" & vBay).Text / Me.Controls("lblTot" & vBay).Text
    If vPrcntRemain >= 0.5 Then
    DirectCast(Me.Controls("pbLight" & vBay), PictureBox).Image = My.Resources.Green
    Else
    If vPrcntRemain >= 0.25 Then
    DirectCast(Me.Controls("pbLight" & vBay), PictureBox).Image = My.Resources.Yellow
    Else
    DirectCast(Me.Controls("pbLight" & vBay), PictureBox).Image = My.Resources.Red
    End If
    End If
    Else
    DirectCast(Me.Controls("pbLight" & vBay), PictureBox).Image = My.Resources.None
    End If

    vActiveUpdate = False


    The goal is to add the Tab Controls, but still update the pbLight Controls using less code, as shown above, rather than updates for each Bay through direct reference,(ie pbLight1.Image, pbLight2.Image....)

    Can this be done using the Tab Control, or should I just go back to Forms and create a second form. Tab Control would be nicer from a user interface (my opinion), but I am more a fan of clean/concise coding.

    Thanks for your help.

  6. #6

    Thread Starter
    Member
    Join Date
    Jun 2013
    Posts
    50

    Re: VB.NET - Migrating from single Form to Tab Control

    My research on the Tab Control states that controls on the various pages must be unique, so it is frustrating that the DirectCast operator does not work.

    EDIT - I thought CallbyName would work, but still can not reference the Object with a variable. Hardcoding the control name in works fine with DirectCast and Callbyname, I just can't figure out how to use a variable.

    Thanks
    Last edited by JosFKirby; Nov 2nd, 2015 at 10:59 AM.

  7. #7
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: VB.NET - Migrating from single Form to Tab Control

    Then let us illustrate. The following creates a form that has 3 tab pages. On each tab page is a Label. Above the TabControl, you will find three buttons. Clicking any of the buttons will toggle the label on the appropriate tab page between red and green. It's set up to look a lot like it would if you'd dragged the controls, but I'm making them myself. You can ignore the parts that I've commented as "You can ignore this", but you might want to peek at them for fun. Later, we'll see how dramatically arrays simplify it.

    Code:
    Public Class Form1
    
        ' This is the array of labels. We will use it to access the labels by number.
        Private _labels() As Label
    
        Public Sub New()
            InitializeComponent()
            SetupControls()
    
            ' We create the array of labels after the labels are created. This is important!
            _labels = {Label1, Label2, Label3}
        End Sub
    
        Private Sub Button_Click(sender As Object, e As EventArgs) Handles Button1.Click, Button2.Click, Button3.Click
            ' Figure out which button we clicked. I've set each button's "Tag" property to
            ' an integer.
            Dim theButton = CType(sender, Button)
            Dim theTag = CInt(theButton.Tag)
    
            ' The integer is the number of the button, which is also the number of the tab page
            ' it edits. But since we count starting at 1, and arrays start at 0, we have to take
            ' 1 off of it.
            Dim theIndex As Integer = theTag - 1
            Dim theLabel As Label = _labels(theIndex)
    
            If theLabel.BackColor = Color.Green Then
                theLabel.BackColor = Color.Red
            Else
                theLabel.BackColor = Color.Green
            End If
        End Sub
    
        ' You can ignore the parts below.
    
        Friend WithEvents Label1 As Label
        Friend WithEvents Label2 As Label
        Friend WithEvents Label3 As Label
    
        Friend WithEvents Button1 As Button
        Friend WithEvents Button2 As Button
        Friend WithEvents Button3 As Button
    
        Private Sub SetupControls()
            Label1 = New Label()
            Label2 = New Label()
            Label3 = New Label()
    
            Button1 = New Button()
            Button2 = New Button()
            Button3 = New Button()
    
            Dim index As Integer = 1
            Dim lastX As Integer = 0
            For Each btn As Button In {Button1, Button2, Button3}
                btn.Text = String.Format("Number {0}", index)
                btn.Location = New Point(lastX + 10, 10)
                btn.Tag = index
                lastX = btn.Right
                Me.Controls.Add(btn)
                index += 1
            Next
    
            Dim tabs As New TabControl()
            tabs.Anchor = AnchorStyles.Bottom Or AnchorStyles.Left Or AnchorStyles.Right
            tabs.Width = Me.ClientRectangle.Width - 20
            tabs.Height = Me.ClientRectangle.Height - 30 - Button1.Height
            tabs.Location = New Point(10, Button1.Bottom + 10)
            Me.Controls.Add(tabs)
    
            index = 1
            For Each lbl As Label In {Label1, Label2, Label3}
                Dim tabPage As New TabPage()
                tabPage.Text = String.Format("Tab {0}", index)
                tabPage.Controls.Add(lbl)
                lbl.Width = 100
                lbl.Height = 100
                lbl.BackColor = Color.Red
                tabs.TabPages.Add(tabPage)
                index += 1
            Next
        End Sub
    
    End Class
    The program creates an array with each label in it at startup. Note that we *had* to set each Button's Tag property to a number, or else we wouldn't have a good way to know which button was clicked. You could also look at the text of the button, or write a big If..Else statement. This is sort of what your vBay variable was doing in your program: obviously no matter what you do you need some variable to control which label you're looking for.

    Now, if we want to go whole hog and use arrays everywhere, this code actually gets more simple and we can do without the Tag setup. We can even change how many tab pages and buttons there are with one variable! I promise if you read this, I'll show you the way that looks more like what you're doing, even though I think it's awful.
    Code:
    Public Class Form1
    
        Private Const NumberOfItems As Integer = 5
    
        Private _buttons() As Button
        Private _labels() As Label
    
        Public Sub New()
            InitializeComponent()
            SetupControls()
        End Sub
    
        Private Sub Button_Click(sender As Object, e As EventArgs)
            ' Figure out which button we clicked. Since they are in the same order
            ' as the labels in their array, the index works.
            Dim index = Array.IndexOf(_buttons, sender)
            Dim theLabel = _labels(index)
    
            If theLabel.BackColor = Color.Green Then
                theLabel.BackColor = Color.Red
            Else
                theLabel.BackColor = Color.Green
            End If
        End Sub
    
        ' You should have a look at the parts below, and compare them to the last example.
    
        Private Sub SetupControls()
            Dim tabs As New TabControl()
            ReDim _buttons(NumberOfItems - 1)
            ReDim _labels(NumberOfItems - 1)
    
            For i As Integer = 0 To NumberOfItems - 1
                _buttons(i) = New Button()
                _buttons(i).Text = String.Format("Button {0}", i + 1)
                _buttons(i).Location = New Point(10 + i * (_buttons(i).Width + 10), 10)
                AddHandler _buttons(i).Click, AddressOf Button_Click
                Me.Controls.Add(_buttons(i))
    
                _labels(i) = New Label()
                _labels(i).Width = 100
                _labels(i).Height = 100
                _labels(i).BackColor = Color.Green
    
                Dim tabPage As New TabPage()
                tabPage.Text = String.Format("TabPage {0}", i + 1)
                tabPage.Controls.Add(_labels(i))
                tabs.TabPages.Add(tabPage)
            Next
    
            tabs.Anchor = AnchorStyles.Bottom Or AnchorStyles.Left Or AnchorStyles.Right
            tabs.Width = Me.ClientRectangle.Width - 20
            tabs.Height = Me.ClientRectangle.Height - 30 - _buttons(0).Height
            tabs.Location = New Point(10, _buttons(0).Bottom + 10)
            Me.Controls.Add(tabs)
        End Sub
    End Class
    It's shorter and simpler, because we let the arrays do the work.

    Now, if what you REALLY want is to write something like your code, and you REALLY want to use the name, then you have to write something that's resilient to your UI changes. That means starting with your Form's controls and descending into anything that has child Controls, also being cognizant of TabPages. It looks something like this, you'd have to redo it a bit for your picture boxes:
    Code:
    Function FindLabel(ByVal controls As Control.ControlCollection, ByVal desiredName As String) As Label
        For Each control As Control In controls
            If control.Name = desiredName Then
                Return CType(control, Label)
            End If
    
            Dim result As Label = Nothing
            If (control.Controls IsNot Nothing) Then
                result = FindLabel(control.Controls, desiredName)
            ElseIf control.GetType() Is GetType(TabControl)
                For Each tabPage As TabPage In CType(control, TabControl).TabPages
                    result = FindLabel(tabPage.Controls, desiredName)
                Next
            End If
    
            If result IsNot Nothing Then
                Return result
            End If
        Next
    
        Return Nothing
    End Function
    I can still think of a few reasons why it might fail, and I didn't test it heavily. I think this is a functional but wrong solution to your problem.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  8. #8

    Thread Starter
    Member
    Join Date
    Jun 2013
    Posts
    50

    Re: VB.NET - Migrating from single Form to Tab Control

    I very much appreciate the depth that you are going to in providing a complete answer, and I apologize in advance if I am missing the core of what you are attempting to explain. I am open to the fact that I am so entrenched in my approach that I am not seeing the path forward. Let me provide a bit more detail on the current application:

    Below is a portion of the form and tab control:


    Name:  TrafficScreen.jpg
Views: 656
Size:  20.6 KB

    This app provides a visual roughly of the bay locations in our shop and allows users to "Dispatch" work to the bay, "Adjust" time if additional work is needed, and shop the job as "Done", when the bay is open again. Up to 4 different users use this system and can make updates, which are stored in a SQL Server Database. Every few seconds, the "Stop Light" controls are updated as either Green, Yellow or Red, depending on the status.

    My code had worked fine until I moved the controls into the TabControl. I can directly reference them, but would rather reference them by variables as shown in my prior code.

    I am using Controls to represent the layout of the shop for all persons viewing the status. I'm not sure how the use of Arrays in this case will change the fact that I need to update the visual control of pbLight1, pbLight2, etc....

    I am open to the fact that I'm completely missing a very basic point that you are trying to help me with, and am waiting for the lightbulb to turn on for me...

    The program is currently in operation and works well for users. I'm expanding it to show another location on my property and thought the tab controls would be a simple way of expanding the bays in operation; not so true. Removing the tab control and just doing this on the form will work, but the tab control does look like a nice way to separate the areas of the shop and provide a simple User Interface.

    I understand that the controls now being on the Tab Pages might need a different way of reference them with the DirectCast, and for the life of me, I can't figure it out. The logic, flow and usefulness of this application is proven. I would just like to get the tab control working; if I can't get the syntax right then I will remove it and go with what works.

    Thank you for your patience.

  9. #9
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: VB.NET - Migrating from single Form to Tab Control

    OK, that picture is actually enlightening, one of the rare examples of a screenshot saying more than code.

    What you used to have, in my reckoning, is all of these controls manually placed on a single form, or maybe multiple forms. What's important about your old way is that all of your controls lived in that form's Controls collection. Since that collection can be indexed by a string, and that string represents the control's name, you could use the control's name as an index and get the control.

    The core point I am trying to make is:

    That only works if all controls are in the same Controls collection. If your form has a GroupBox, the controls in that GroupBox do not exist in the Form's Controls collection. If your form has a Panel, the controls in that Panel do not exist in the Form's Controls collection.

    So it looks like to get to your bay indicators in the manner in which you are accustomed, you'd have to:
    1. Look up the tab page you want in the TabControl's TabPages collection.
    2. Look up the groupbox you want in the TabPage's Controls collection.
    3. Look up the picturebox you want in that GroupBox's Controls collection.

    I'm not sure, but I think there's actually another layer there. In short: this gets really complex really fast, and isn't the right approach.

    By analogy:

    Imagine you have a box of cookies, and each cookie has a different number on it. If I ask you, "Look in the box, and find cookie #3. Take it out and eat it", there's no problem. You look in the box, get cookie #3, and eat a nice cookie. Now imagine you have a box in which there are 10 unopened boxes of cookies, and every cookie has a different number. If I ask you, "Look in the box and take out cookie #3", you're going to have to do some thinking. Technically the box doesn't have cookies, it has more boxes. You could decide to open one of the boxes, but I didn't say that, did I? Humans might assume I meant to open a box. Computers do not assume.

    So, your old project was like one big box of controls. Your new project is a box that contains some controls and some boxes that contain other controls and some boxes that contain other controls. You only have two logical ways to approach this.

    One way involves what you might do with the box of boxes of cookies when I ask for #3. You could open a box, and see if it has cookie #3 inside. If it doesn't, you open another box, and see if THAT box has #3. Maybe one box of cookies has a smaller box of cookies inside. You'd look inside that too. That's what the code at the very end of my post does: it starts looking at every control in the form. If one of those controls has other controls inside, it looks at those controls. If any of THOSE controls have other controls inside, it looks at those, and so on.

    Another way involves what you might do if I often ask for very specific cookies and you're tired of looking very hard. In this world, when you get your case of boxes of cookies with smaller boxes of cookies inside, you say "Forget leaving these unopened" and crack them all, carefully sorting each cookie into a bin that helps you find the one I'm going to ask for faster. So when I ask for cookie #3, you look for bin #3 and deliver. If I ask for #5, you've got me covered. This is what I'm trying to nudge you towards with arrays.

    There is another way I haven't talked about that would exploit an API called Reflection and the designer-generated variable names. I'm not going to talk about it, because by analogy it's the same as if when I ask for cookie #3 you call the cookie factory and ask them to deliver a #3 to us. It's a LOT of work, it moves VERY slowly, and if you don't understand arrays you're going to be completely lost with reflection.

    But there's no getting around it: If your controls are not all in the exact same Controls collection, there is no one-line technique for using the control name or even a number to reference the control. If you want that in .NET, you HAVE to create an array, or list, or dictionary, or any other data structure. Alternatively, you can write a beast of a recursive lookup method, but that's prone to breaking every time you make a layout change.

    The reason I'm not revealing a one-line solution to you is it doesn't exist. I promise I'm not being difficult just to watch you try writing some different code. If there were a one-line solution, even if I hated it, by now I'd have begrudgingly listed it and said, "But you really shouldn't do it this way", just like I did with my recursive code above. You're going to have to try some form of the code I posted and figure out how to make it work in your situation. My opinion is if you'd have started working on typing out the control array, you'd have been finished by now. I don't really care which solution you try, but that one's more reliable and likely to work without a lot more back-and-forth.

    But if what you really want is a one-line solution, there's no answer.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  10. #10

    Thread Starter
    Member
    Join Date
    Jun 2013
    Posts
    50

    Re: VB.NET - Migrating from single Form to Tab Control

    That helps a great deal. You have helped me define reality and understand the complexity that was built in by my use of the groupbox and page tabs.

    I will figure out a path forward within my capabilities. :-)

    Joe

  11. #11
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: VB.NET - Migrating from single Form to Tab Control

    I think I would still go with Sitten Spynne array approach, which is what I always do (or lists or dictionaries instead of explicit arrays, depending on the need) to handle maintaining items that I want to access based on some ID or index.

    In your case, you could just gather the Bay related items together so you can access them as an indexed group.
    You currently have essentially a number of parallel arrays of controls you are accessing by bay number.

    You could keep it that way, actually, by creating the arrays for each of the things you access, the labels and pictureboxes, but I would gather the bay related items into a simple class, and create an array of the class accessing the class instance using the bay number.

    I think a code illustration would probably work best here, and since you provided some example code in Post #5, this example is based on converting that code.
    It hardcodes the setting of the items in the class to which controls you want them to map to (only did the first two for the example).
    And modified the code to use the vBay to get the array index, and then access each control using the members of the class.
    Code:
    Option Strict Off
    
    Public Class Form1
      Private vActiveUpdate As Boolean
      Private TimeSpan As TimeSpan
      Private vMin As Integer
      Private vPrcntRemain As Single
    
      Private vBay As Integer
    
      Private Class BayClass
        Public lblTot As Label
        Public dtTime As DateTimePicker
        Public lblRemain As Label
        Public pbLight As PictureBox
      End Class
    
      Private Bay(5) As BayClass
    
      Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    
        Bay(0) = New BayClass
        With Bay(0)
          .lblTot = lblTot1
          .lblRemain = lblRemain1
          .pbLight = pbLight1
          .dtTime = dtTime1
        End With
    
        Bay(1) = New BayClass
        With Bay(1)
          .lblTot = lblTot2
          .lblRemain = lblRemain2
          .pbLight = pbLight2
          .dtTime = dtTime2
        End With
    
        lblTot1.Text = "200"
        lblTot2.Text = "400"
        vBay = 2
       
      End Sub
    
      Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    
        vActiveUpdate = True
    
        Dim BayIdx As Integer = vBay - 1
        With Bay(BayIdx)
          If .lblTot.Text > 0 Then
            TimeSpan = Now().Subtract(.dtTime.Value)
            vMin = (TimeSpan.Days * 1440) + (TimeSpan.Hours * 60) + (TimeSpan.Minutes)
            .lblRemain.Text = .lblTot.Text - vMin
            vPrcntRemain = .lblRemain.Text / .lblTot.Text
            If vPrcntRemain >= 0.5 Then
              .pbLight.Image = My.Resources.Green
            Else
              If vPrcntRemain >= 0.25 Then
                .pbLight.Image = My.Resources.Yellow
              Else
                .pbLight.Image = My.Resources.Red
              End If
            End If
          Else
            .pbLight.Image = My.Resources.None
          End If
        End With
    
        vActiveUpdate = False
      End Sub
    
    End Class
    This is just another variation on what Sitten Spynne has been explaining. Perhaps mapping your code more directly into this example might help make the benefits more evident.

    p.s. I had to turn Option Strict Off (I have it defaulted to on), but because VB normally defaults it to Off "out of the box", newer users end up depending on implicit conversions which is actually not a good thing. If you're going to revamp the code a bit using arrays to make the code more flexible/extensible in the future, it might also be a good time to add Option Strict On at the top of your file (or better yet, just default it to On in your IDE environment), so you can weed out implicit narrowing conversions from your code. Its not "strictly" necessary at this point, but something to consider as you progress.
    Last edited by passel; Nov 2nd, 2015 at 03:33 PM.

  12. #12

    Thread Starter
    Member
    Join Date
    Jun 2013
    Posts
    50

    Re: VB.NET - Migrating from single Form to Tab Control

    Thank you for the reply. I'm going to complete the program using the approach I know at this time to get it operational. Then, it makes sense to come back around and explore a more efficient approach.

    I'm going to look further into your suggestions above to more fully understand the concept, and then perhaps start a new thread asking for input with a revised design.

    Thanks for all the input.

    Joe

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width