I have a form containing a tab control, which itself contains five tab pages. These tab pages contain lists, textboxes, and other controls that I update when the user enters the relevant page.

One of the tab pages contains a textbox which I fill with information from an external text file. This information is a 'log' of changes made to documents sorted chronologically so that the most recent change is found at the bottom of the log. When the user enters this tab page, the textbox is filled with information from the external text file (it does this every time to keep the log the user sees up-to-date) and I would then like to scroll to the bottom of the textbox. The code I use to do this works and is:

Dim sr As StreamReader = My.Computer.FileSystem.OpenTextFileReader(My.Settings.logFilePath)
ChangeLogBox.Text = sr.ReadToEnd()
sr.Close()
ChangeLogBox.SelectionStart = ChangeLogBox.Text.Length
ChangeLogBox.ScrollToCaret()

The problem I'm having is that the textbox, now revealed as ChangeLogBox, won't scroll to the bottom when this code is contained within the TabPage.Enter event handler. However, it WILL scroll to the bottom if the code is contained within the TabControl.SelectedIndexChanged event handler. It also scrolls to the bottom if the code is run from a button control on the tab page.

I imagine the problem is something to do with the fact that I'm attempting to use methods associated with the ChangeLogBox object before the control has properly loaded on the form. In which case, is there a way to determine whether or not the control has loaded and will respond to the ScrollToCaret() request?

I've also tried the GotFocus, Validated, and LostFocus event handlers and none of them solve the problem. In fact, these events don't even seem to fire when the tab page is selected (weirdly). I only seem to have this issue when scrolling to the caret. I'm able to successfully update other controls on this tab page and others via the Enter event handler.

The entire event handler is:

    Private Sub ChangelogPage_Enter() Handles ChangelogPage.Enter
        Dim initialised As Boolean = False

        If My.Settings.enableAutoRefresh Then
            If Not changelogListRefreshed Then
                While Not initialised
                    Try
                        ChangelogListUpdate()
                        LoadLog()
                        initialised = True
                        NetworkTimeout.Stop()
                    Catch ex As IOException
                        ' Start time-out timer
                        If Not NetworkTimeout.Enabled Then
                            NetworkTimeout.Start()
                        End If
                    End Try
                End While
            End If
        End If

        ChangelogRefreshButton.Visible = True
        DescriptionTip.SetToolTip(ChangelogRefreshButton, _
                                  "REFRESH Changelog")
        FoundLogBox.Text = Nothing
        ' Force redraw of tabpage so that colours display
        ChangelogList.Refresh()
    End Sub

enableAutoRefresh is a setting that is True in this case, so may as well be ignored. changelogListRefreshed is a variable used to stop this update when the user leaves the tab page (again, weirdly, the Enter event seems to fire when the tab page is left as well as entered) and is False upon entering the tab page and True when leaving. The Try... Catch block is used just in case the text file being read from is inaccessible (temporarily).

The LoadLog() method is:

    Friend Sub LoadLog()
        Dim initialised As Boolean = False

        While Not initialised
            Try
                Dim sr As StreamReader = _
                    My.Computer.FileSystem.OpenTextFileReader( _
                        My.Settings.logFilePath)
                ChangeLogBox.Text = sr.ReadToEnd()
                sr.Close()
                ChangeLogBox.SelectionStart = ChangeLogBox.Text.Length
                ChangeLogBox.ScrollToCaret()
                initialised = True
                NetworkTimeout.Stop()
            Catch ex As IOException
                ' Start time-out timer
                If Not NetworkTimeout.Enabled Then
                    NetworkTimeout.Start()
                End If
            End Try
        End While
    End Sub

I've been struggling with this for a while and would appreciate any pointers or ideas!

It appears your main problem is not qualifying the textbox as belongiong to the tabpage. Something like this might work:

Friend Sub LoadLog()
    Dim initialised As Boolean = False
    Dim CLB As TextBox = DirectCast(ChangelogPage.Controls("ChangeLogBox"), TextBox)
    While Not initialised
        Try
            Dim sr As StreamReader = _
            My.Computer.FileSystem.OpenTextFileReader( _
            My.Settings.logFilePath)
            CLB.Text = sr.ReadToEnd()
            sr.Close()
            CLB.SelectionStart = CLB.Text.Length
            CLB.ScrollToCaret()
            initialised = True
            NetworkTimeout.Stop()
        Catch ex As IOException
            ' Start time-out timer
            If Not NetworkTimeout.Enabled Then
                NetworkTimeout.Start()
            End If
        End Try
    End While
End Sub

That behaves in exactly the same manner, I'm afraid.

I have managed to work around the problem somewhat in just using the following statement in the TabControl.SelectedIndexChanged event handler:

If TabControl1.SelectedIndex = 3 Then
    LoadLog()
End If

While this has solved the overall behaviour issue, I would still like to know why my first attempt (using the Enter event handler) isn't working!

This article has been dead for over six months. Start a new discussion instead.