Results 1 to 5 of 5

Thread: Problem declaring list to have form level scope.

  1. #1

    Thread Starter
    Junior Member
    Join Date
    Sep 2013
    Posts
    21

    Problem declaring list to have form level scope.

    Hi,
    N00b issue; I don’t seem to be able to give the correct scope when defining a collection/list.
    The list holds a group of references to textboxes.

    Code:
    Dim TBDec1 As New List(Of TextBox)() From {TBDecMsg1B7, TBDecMsg1B6, TBDecMsg1B5, TBDecMsg1B4, TBDecMsg1B3, TBDecMsg1B2, TBDecMsg1B1, TBDecMsg1B0}
    The program works if this is declared within each procedure that requires it.
    In an attempt to tidy up, I wish to declare it with a wider scope. I assumed form level would suffice and placed the follow, immediately after the ‘Public Class Form1’ line.
    Code:
    Private TBDec1 As New List(Of TextBox)() From {TBDecMsg1B7…. Etc
    I tried DIM, PRIVATE
    I also tried (badly) to create a module to hold this ‘global’ variable…no luck as it clearly had no knowledge of the textboxes references by the declaration.

    Each time I run, I get;
    Code:
    System.NullReferenceException: 'Object reference not set to an instance of an object.'
    Clearly, when a variable is being used to retrieve an item from the list and its not able to find the list, even though I though I have it declared and at a quite broad level.
    Am I missing something obvious here ?
    How would you declare a list of textboxes at a broad level that will cover most of my 'windows forms' project?
    Thanks for any guidance. - please excuse incorrect use of terminology.

  2. #2
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    26,413

    Re: Problem declaring list to have form level scope.

    Your textboxes don't exist if you declare them at form level. Form level variables are processed before the form's InitializeComponent method. All of your form controls are created in InitializeComponent...

    Code:
    Public Class Form1
    
        Dim TBDec1 As New List(Of TextBox)
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            TBDec1.AddRange(New TextBox() {TBDecMsg1B7, TBDecMsg1B6, TBDecMsg1B5, TBDecMsg1B4, TBDecMsg1B3, TBDecMsg1B2, TBDecMsg1B1, TBDecMsg1B0})
        End Sub
    
    End Class

  3. #3
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,102

    Re: Problem declaring list to have form level scope.

    The other place you could put this is in the constructor for the form (Sub New), which is typically found in the .designer.vb file, unless you have created your own constructor.

    There probably isn't all that much difference between the two, but the constructor is run when you create the form, whereas the Load event is raised when you show the form. Typically showing follows closely after creation, but it doesn't have to, which can be convenient.
    My usual boring signature: Nothing

  4. #4

    Thread Starter
    Junior Member
    Join Date
    Sep 2013
    Posts
    21

    Re: Problem declaring list to have form level scope.

    oh, Good to know, thanks. J.

  5. #5
    Karen Payne MVP kareninstructor's Avatar
    Join Date
    Jun 2008
    Location
    Oregon
    Posts
    6,713

    Re: Problem declaring list to have form level scope.

    Another idea is if you want all TextBox controls on a form to be in the List(Of TextBox) including those in panels and or group boxes add the following code module to the project.

    Code:
    Public Module ControlExtensions
    
        ''' <summary>
        ''' Provides access to all controls on a form including
        ''' controls within containers e.g. panel and group box etc.
        ''' </summary>
        ''' <typeparam name="T"></typeparam>
        ''' <param name="control"></param>
        ''' <returns></returns>
        <Runtime.CompilerServices.Extension>
        Public Iterator Function Descendants(Of T As Class)(control As Control) As IEnumerable(Of T)
            For Each child As Control In control.Controls
    
                Dim currentChild = TryCast(child, T)
                If currentChild IsNot Nothing Then
                    Yield currentChild
                End If
    
                If child.HasChildren Then
                    For Each descendant As T In child.Descendants(Of T)()
                        Yield descendant
                    Next
                End If
            Next
        End Function
    End Module
    Then to use it for all TextBox controls on a form.

    Code:
    Public Class Form1
        Private TextBoxList As New List(Of TextBox)
        Public Sub New()
            InitializeComponent()
    
            TextBoxList = Descendants(Of TextBox).ToList()
            For Each textBox As TextBox In TextBoxList
                AddHandler textBox.TextChanged, AddressOf GeneralTextBox_TextChanged
            Next
    
    
        End Sub
        Private Sub GeneralTextBox_TextChanged(sender As Object, e As EventArgs)
            Console.WriteLine(
                $"Value for {CType(sender, TextBox).Name} is '{CType(sender, TextBox).Text}'")
        End Sub
    End Class
    To get nothing off the form directly, get TextBox controls in a single panel and a single group box.

    Code:
    Public Sub New()
        InitializeComponent()
    
        TextBoxList = Panel1.Descendants(Of TextBox).ToList()
        TextBoxList.AddRange(GroupBox1.Descendants(Of TextBox))
    
        For Each textBox As TextBox In TextBoxList
            AddHandler textBox.TextChanged, AddressOf GeneralTextBox_TextChanged
        Next
    End Sub

Tags for this Thread

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