Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 225
  • Last Modified:

Quick 500 - Need help on Threading; a nice puzzle for you guru's :)

Hi,

I'm been working on a CommandButton UserControl that is passed a stored procedure. When a button is pressed, It calls the Results from the database and then displays the information in a seperate form which is then aligned to the UserControl.

This is all working until today when i decided that i wanted the Database call which takes a few seconds to be done in a seperate thread... Everything is working fine, but by the time the Call finishes the forms are flashing visible then disappearing.

I've tracked the point in which the forms disappear, there are no dispose calls being made or anything like that, unfortunatly this is where it gets interesting... the Forms are disappearing when the cursor ends a subroutine.

I've made a simple peice of code for you guys to compile
You need to breakpoint the 'End Sub' which i've clearly marked

Do the following....
Make a normal Windows Project
Add another project to the solution - Select Windows Control Library
In the new UserControl... Draw a new button (no need to rename)

now go into the Code of the USer control and Paste the Following:


'***************************************************

        Private Delegate Sub DataSet_WorkCompleted(ByVal ObjRows() As DataRow)
        Private m_ResultCallback As DataSet_WorkCompleted
        Private ObjSearchResults As SearchResults
    Private WithEvents ObjFrmResults As New Form1

    Private Sub Cmd_Search_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        'The Search button was Clicked.. Open the Wrapper and Populate it with the Parameters and SP info
        Try

            m_ResultCallback = AddressOf Populate_Results
            ObjSearchResults = New SearchResults(m_ResultCallback)
            Dim ObjThread As New Threading.Thread(AddressOf ObjSearchResults.Search)
            ObjThread.Start()
            'ObjSearchResults.Search()

        Catch ex As Exception
            'Error stuff
        End Try
    End Sub

    Private Sub Populate_Results(ByVal ObjDataRows() As Data.DataRow)
        'Show the form
        ObjFrmResults.Show()
        ObjFrmResults.TopMost = True
    End Sub


    Private Class SearchResults
        Private m_CallBackThread As DataSet_WorkCompleted

        Public Sub New(ByRef CallBackWhenCompleted As DataSet_WorkCompleted)
            m_CallBackThread = CallBackWhenCompleted
        End Sub
        Public Sub Search()
            Dim ObjRow(5) As DataRow

            'This is where the DB call goes...
            System.Threading.Thread.Sleep(5000)

            'By now the ObjRow would be populated also...

            m_CallBackThread(ObjRow)


        End Sub 'BREAKPOINT HERE <-------
    End Class

'**************************
Now... Rebuild the solution and paste the Usercontrol onto the first project's form....

After breakpointing the 'End Sub' that i've marked.... Run the project and click the Button, You should see a new form (topmost for debug) appear on top of the existing form and the breakpoint kick off...

This is where my results are displayed.... but as soon as you Step through so the cursor goes past the End Sub, the Form disappears

I think this is something to do with the GC killing it all off because the form is obviously running on the same thread (my best guess) but i can't figure out how to make the form stay :/

If you can figure out this little puzzle the 500 is yours :D

Thanks in Advance
0
Cloud9_User
Asked:
Cloud9_User
1 Solution
 
LacutahCommented:
The problem is that your created thread is trying to alter the user interface.  Only the main thread can alter the user interface ( Private Sub Populate_Results)

One way around this is the use of delegates - when the data has been retrieved, having the created thread call ObjFrmResults.Invoke(Delegate), which would force the called delegate to run under the main thread.

The other way is to create a delegate and use it's BeginInvoke and EndInvoke.
Here's an example on how to do it - I am not using the class you created in your code above, so it's a bit simpler:
    'Define a delegate Structure
    Private Delegate Function delSearch() As DataRow()
    'Create a Delegate Object of type delSearch
    Private d As New delSearch(AddressOf GetData)
    Sub Cmd_Search_Click()  'Whatever event should start the ball rolling.
        'The following cruns GetData on a seperate thread, and when
        'done executing, calls HasData on the current thread.
        d.BeginInvoke(New AsyncCallback(AddressOf HasData), Nothing)
    End Sub
    'This function will run on a seperate thread.
    Function GetData() As DataRow()
        '... Get Data Here ..., return DataRows...
        'Return SomeRows
    End Function
    Sub HasData(ByVal ar As IAsyncResult)
        'The next line retrieves the datarows from the non-ui thread...
        Dim myDataRows() As DataRow = d.EndInvoke(ar)
        ObjFrmResults.Show()
        ObjFrmResults.TopMost = True
    End Sub
0
 
Cloud9_UserAuthor Commented:
Brilliant.... the First example solved my Problem, except in my Actual code i'm passing the UserControl anyway... So i just did UserControl.Invoke

Thanks!
0

Featured Post

Receive 1:1 tech help

Solve your biggest tech problems alongside global tech experts with 1:1 help.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now