Async process - Start Subroutine when finished

  • Thread starter Thread starter Marcolino
  • Start date Start date
Hi All,
I'm using this code provided by Michael to run Async process:

http://groups.google.com/group/microsoft.public.dotnet.languages.vb/b...

Now I have a new need. I have to start a Soubroutine when the Async
process is finished.

Many Thanks.

--Marco

You can set up a callback from the BeginInvoke call that will fire
when the async process finishes. Then you can do whatever you need
from that method:

Here's a quick console demo app:

////////////////
Option Strict On

Module Module1

Public Delegate Sub AsyncDelegate()

Sub Main()
Console.WriteLine("Starting")
Dim worker As New AsyncDelegate(AddressOf AsyncMethod)
worker.BeginInvoke(New AsyncCallback(AddressOf
AfterAsyncMethod), Nothing)
Console.WriteLine("Asnyc called")

Console.Read()
End Sub

Private Sub AfterAsyncMethod(ByVal ar As IAsyncResult)
Console.WriteLine("AsyncMethod finished. Do something else")
End Sub

Private Sub AsyncMethod()
Console.WriteLine("Async is working")
'// Simulate work
System.Threading.Thread.Sleep(1500)
Console.WriteLine("Async is done working")
End Sub

End Module
////////////////

Thanks,

Seth Rowe [MVP]
 
Private Sub AfterAsyncMethod(ByVal ar As IAsyncResult)
Console.WriteLine("AsyncMethod finished. Do something else")
End Sub

Should call EndInvoke here - to clean up the Async handler?
 
Marco,
You can also play with BackgroundWorker control and its events such as
RunWorkerCompleted, ProgressChanged events if it helps you.

Regards,

Onur Güzel

Hi I tryed this:
worker.BeginInvoke(New AsyncCallback(AddressOf AfterAsyncMethod),
Nothing)

but i have a little problem.
During sub AfterAsyncMethod() i need to populate a listview present on
main form. This is not possible because I cannot execute cross tread
operation.
I need that AfterAsyncMethod() will be executed on the main tread of
the application, after my async process is finished.

Thanks a lot
 
Should call EndInvoke here - to clean up the Async handler?

Oops, I swear I meant that to be in there!

Note to the OP, you'll have to move worker out of method scope and as
a private class variable so you can access it's EndInvoke method.

Thanks,

Seth Rowe [MVP]
 
Hi I tryed this:
worker.BeginInvoke(New AsyncCallback(AddressOf AfterAsyncMethod),
Nothing)

but i have a little problem.
During sub AfterAsyncMethod() i need to populate a listview present on
main form. This is not possible because I cannot execute cross tread
operation.
I need that AfterAsyncMethod() will be executed on the main tread of
the application, after my async process is finished.

Thanks a lot

You need to invoke control back to the form. Here's a sample form that
demonstrates (changes title to "hello, world" after 1.5 seconds).

//////////////////////
Public Class Form1

Public Delegate Sub SimpleDelegate()
Dim worker As SimpleDelegate

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
worker = New SimpleDelegate(AddressOf AsyncMethod)
worker.BeginInvoke(New AsyncCallback(AddressOf
AfterAsyncMethod), Nothing)
End Sub

Private Sub AfterAsyncMethod(ByVal ar As IAsyncResult)
worker.EndInvoke(ar)

If Me.InvokeRequired Then
Dim formWorker As New SimpleDelegate(AddressOf
StuffToDoOnTheForm)
Me.BeginInvoke(formWorker)
Else
StuffToDoOnTheForm()
End If
End Sub

Private Sub AsyncMethod()
'// Simulate work
System.Threading.Thread.Sleep(1500)
End Sub

Private Sub StuffToDoOnTheForm()
Me.Text = "hello, world"
End Sub

End Class
//////////////////////

Thanks,

Seth Rowe [MVP]
 
Oops, I swear I meant that to be in there!

Note to the OP, you'll have to move worker out of method scope and as
a private class variable so you can access it's EndInvoke method.

Thanks,

Seth Rowe [MVP]

Sorry Rowe,
I'm not English and I have not understand your last post.
In any case i look around google for my problema but i can find
anything. Probably I'm searching the wrong thing.
My need is so simple:

During sub AfterAsyncMethod() i need to populate a listview present
on
main form. This is not possible because I cannot execute cross tread
operation.
I need that AfterAsyncMethod() will be executed on the main tread of
the application, after my async process is finished.

but I cannot understand how implement.

Thanks
 
Sorry Rowe,
I'm not English and I have not understand your last post.
In any case i look around google for my problema but i can find
anything. Probably I'm searching the wrong thing.
My need is so simple:

During sub AfterAsyncMethod() i need to populate a listview present
on
main form. This is not possible because I cannot execute cross tread
operation.
I need that AfterAsyncMethod() will be executed on the main tread of
the application, after my async process is finished.

but I cannot understand how implement.

Thanks- Hide quoted text -

- Show quoted text -

Did you try my sample code? It shows how to marshall control back to
the form, preventing the cross thread exceptions.

Thanks,

Seth Rowe [MVP]
 
Did you try my sample code? It shows how to marshall control back to
the form, preventing the cross thread exceptions.

Thanks,

Seth Rowe [MVP]- Nascondi testo tra virgolette -

- Mostra testo tra virgolette -

HI rowe,
I'm referring to your previus post.
I'll try the code this morning


Thanks
 
HI rowe,
I'm referring to your previus post.
I'll try the code this morning

Thanks- Nascondi testo tra virgolette -

- Mostra testo tra virgolette -

Hi rowe,
I tryed your procedure and seems it works. But I have a problem.
During Async process I'll populate a OleDBDatareader declared as
Private Variable on my class.
Datareader was populated fine, but is not possible to access it from
another tread. Damnd M$.
This is my case: http://www.tbiro.com/Unoptimize-data-access-code.htm

So my guess now is to try the other way, populating the ListView on
the form with data in datareader from the async process, but I dont
know how.
Do you have any Idea?

Thanks
 
Hi rowe,
I tryed your procedure and seems it works. But I have a problem.
During Async process I'll populate a OleDBDatareader declared as
Private Variable on my class.
Datareader was populated fine, but is not possible to access it from
another tread. Damnd M$.
This is my case:http://www.tbiro.com/Unoptimize-data-access-code.htm

So my guess now is to try the other way, populating the ListView on
the form with data in datareader from the async process, but I dont
know how.
Do you have any Idea?

Thanks- Hide quoted text -

- Show quoted text -

In my opinion, have any of the Db objects in a private class variable
is a bad idea. Before I go on to say what you should do, it's
important for me to know what the datareader is for? Is this being
populated by some other method (say the Async process)?

Thanks,

Seth Rowe [MVP]
 
In my opinion, have any of the Db objects in a private class variable
is a bad idea. Before I go on to say what you should do, it's
important for me to know what the datareader is for? Is this being
populated by some other method (say the Async process)?

Thanks,

Seth Rowe [MVP]- Nascondi testo tra virgolette -

- Mostra testo tra virgolette -

HI rowe,
i try to explain. I have to run a heavy process that execute a query
to populate a Datareader. I would like to run it in a separate process
why i would not to hang application, and show a progres bar animation
during this process. I need also to populate a Listview, with data
contained in datareader.

Let me know if my explanation is enough.

Marco
 
HI rowe,
i try to explain. I have to run a heavy process that execute a query
to populate a Datareader. I would like to run it in a separate process
why i would not to hang application, and show a progres bar animation
during this process. I need also to populate a Listview, with data
contained in datareader.

Let me know if my explanation is enough.

Marco- Nascondi testo tra virgolette -

- Mostra testo tra virgolette -

Hi rowe,
i had an idea. I would like to use a temporary table into DB to store
the result of a query.
Then i'll call the Sub that populate Listview reading data from the
table. The process could be much more time expensive, but I would not
have any problem accessing to Form Object from Async process.
What do you think?

Thanks
 
Hi rowe,
i had an idea. I would like to use a temporary table into DB to store
the result of a query.
Then i'll call the Sub that populate Listview reading data from the
table. The process could be much more time expensive, but I would not
have any problem accessing to Form Object from Async process.
What do you think?

Thanks

Here's another sample, It assumes a listview with the "listView1"
exists on the form. It'll also need the OleDb object properties set
properly before it'll work but other than that it should be good to
go.

Basically, it passes a DataTable around that will hold the values you
need from the long running OleDb actions. The sample uses the
OleDbDataAdapter to fill the table.

////////////////////
Option Strict On

Imports System.Data
Imports System.Data.OleDb

Public Class Form1

Private worker As WorkerDelegate

Public Delegate Sub WorkerDelegate(ByVal table As DataTable)

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Dim table As New DataTable()
worker = New WorkerDelegate(AddressOf AsyncMethod)

worker.BeginInvoke(table, New AsyncCallback(AddressOf
AfterAsyncMethod), table)
End Sub

Private Sub AfterAsyncMethod(ByVal ar As IAsyncResult)
worker.EndInvoke(ar)
Dim table As DataTable = DirectCast(ar.AsyncState, DataTable)

If Me.InvokeRequired Then
Dim formWorker As New WorkerDelegate(AddressOf
UpdateListView)
Me.BeginInvoke(formWorker, table)
Else
UpdateListView(table)
End If
End Sub

Private Sub AsyncMethod(ByVal table As DataTable)
Using conn As New OleDbConnection("connection string")
Using com As OleDbCommand = conn.CreateCommand()
conn.Open()

com.CommandType = CommandType.StoredProcedure
com.CommandText = "getSomething"

com.Parameters.Add("@SomeParam",
OleDbType.VarChar).Value = "some value"

Using da As New OleDbDataAdapter(com)
da.Fill(table)
End Using
End Using
End Using
End Sub

Private Sub UpdateListView(ByVal table As DataTable)
Me.Text = "Updated"

For Each row As DataRow In table.Rows
'// add the items to the listview
Me.listView1.Items.Add(row(0).ToString())
Next
End Sub

End Class
///////////////////

Thanks,

Seth Rowe [MVP]
 
Here's another sample, It assumes a listview with the "listView1"
exists on the form. It'll also need the OleDb object properties set
properly before it'll work but other than that it should be good to
go.

Basically, it passes a DataTable around that will hold the values you
need from the long running OleDb actions. The sample uses the
OleDbDataAdapter to fill the table.

////////////////////
Option Strict On

Imports System.Data
Imports System.Data.OleDb

Public Class Form1

    Private worker As WorkerDelegate

    Public Delegate Sub WorkerDelegate(ByVal table As DataTable)

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
        Dim table As New DataTable()
        worker = New WorkerDelegate(AddressOf AsyncMethod)

        worker.BeginInvoke(table, New AsyncCallback(AddressOf
AfterAsyncMethod), table)
    End Sub

    Private Sub AfterAsyncMethod(ByVal ar As IAsyncResult)
        worker.EndInvoke(ar)
        Dim table As DataTable = DirectCast(ar.AsyncState, DataTable)

        If Me.InvokeRequired Then
            Dim formWorker As New WorkerDelegate(AddressOf
UpdateListView)
            Me.BeginInvoke(formWorker, table)
        Else
            UpdateListView(table)
        End If
    End Sub

    Private Sub AsyncMethod(ByVal table As DataTable)
        Using conn As New OleDbConnection("connection string")
            Using com As OleDbCommand = conn.CreateCommand()
                conn.Open()

                com.CommandType = CommandType.StoredProcedure
                com.CommandText = "getSomething"

                com.Parameters.Add("@SomeParam",
OleDbType.VarChar).Value = "some value"

                Using da As New OleDbDataAdapter(com)
                    da.Fill(table)
                End Using
            End Using
        End Using
    End Sub

    Private Sub UpdateListView(ByVal table As DataTable)
        Me.Text = "Updated"

        For Each row As DataRow In table.Rows
            '// add the items to the listview
            Me.listView1.Items.Add(row(0).ToString())
        Next
    End Sub

End Class
///////////////////

Thanks,

Seth Rowe [MVP]- Nascondi testo tra virgolette -

- Mostra testo tra virgolette -

Hi Rowe,
very intresting example. My question is:
I have to load around 1 milion of record. Is DataTable too memory
expensive to do this?
Now I'm trying my way with temporary table and it seems to work, but
I'll try also your way.
Thanks
 
Hi Rowe,
very intresting example. My question is:
I have to load around 1 milion of record. Is DataTable too memory
expensive to do this?
Now I'm trying my way with temporary table and it seems to work, but
I'll try also your way.
Thanks

Only way to find out is to try it :-)

Though I really wonder if it's necessary to return 1million records,
do you really expect the user to be able to process that much
information?

Thanks,

Seth Rowe [MVP]
 
Back
Top