Jump to content
Xtreme .Net Talk

Recommended Posts

Posted

Hi There,

 

I have a thread which executes a class. I have another thread which starts a timer (system.timers.time). I also have a textbox on the form which, when the elapsed event of the timer is called, will increment.

 

Basically, what I want to be able to do is graphically represent to the user that the process is running (because this process can take several hours to run), and to display the elapsed time.

 

The problem I have, is that the class thread starts, and then the timer thread starts; and the timer clicks over a few increments, and then doesn't get called for a while (while the class is being executed), and then, once the class has finished executing, the timer 'catches up', and quickly increments to the actual elapsed time, and then all threads are stopped as a result of calling the FinishedLoading event handler.

 

I don't know how I should call get this working so that the timer can continue to increment whilst the class is being executed.

 

My code snippet is as follows:

 

public Thread1 as Threading.Thread
public ThreadTimer as Threading.Thread
private event FinishedLoading()
dim Timer as Timers.Timer

Public Sub New(byval parent as frmMain)
 Thread1 = new System.Threading.Thread(AddressOf CreateDDBatch)
 ThreadTimer = new System.Threading.Thread(AddressOf Timer1Start)
 AddHandler FinishedLoading, AddressOf FinishedLoadingEH
 Thread1.Start()
 ThreadTimer.Start()
End Sub

Private Sub CreateDDBatch()
 Dim DDProcessor as new clsID_DD_AutoProcessor(username, password)
 RaiseEvent FinishedLoading()
End Sub

Sub FinishedLoadingEH()
 ThreadTimer.Abort()
 Timer1.Stop()
 Me.Cursor = Windows.Forms.Cursors.Default
 Me.btnClose.Enabled = True
 Thread1.Abort()
End Sub

Private Sub Timer1Start()
 Timer = New System.Timers.Timer(100)
 AddHandler Timer.Elapsed, AddressOf TimerTick
 Timer.Start()
End Sub

Private Sub TimerTick(ByVal sender as Object, ByVal e as Timers.ElapsedEventArgs)
 Try
   tbTimer.text = cint(tbTimer.text) + 1
 Catch ex as Exception
 End Try
End Sub

 

 

Please try and respond asap with some assistance.

 

Thanks very much,

Michelle

Posted

Further to problem...

 

Hi there.

 

Well, I have figured out what the problem is, but don't know how to fix it!!

 

I have slightly modified the code from above, such that the timer does not run on a separate thread - i just call Timer1Start() instead of ThreadTimer.Start().

 

Now, in remembering that, the timer does appear to handle the timer.elapsed event continually whilst the thread is running (calling the class).

 

The reason that I know this is because I created a small console application using exactly the same code as my windows app, and dumped to the console a) when the thread begins, b) an incrementing int when the timer.elapsed event is called, and, c) when the thread finishes.

 

This shows the output as...

Starting the Thread...

Starting the Timer...

****************

Calling the Class

1

2

3

4

.

.

.

7428

7429

Finished Calling the Class.

 

Therefore, the timer does increment whilst the thread is running.

 

My problem now appears to be that when the timer.elapsed event is handles, I want a textbox on my windows form to increment each time the event is handled so the user knows something is happening.

What is happening, though, is that once the class is called, the textbox stops refreshing with the new value. It only catches up once the class is finished being called.

 

I tried using the following lines of code, which, according to other threads, should have worked:

Timer.SynchronizingObject = Me

and

Timer.SynchronizingObject = tbTimer

But, neither of them made the program run any differently.

 

 

How on earth can I get the tbTimer textbox to display the increments each time the timer.elapsed event is handled - because, the event is being handled, the textbox just isn't displaying the new text.

 

 

Thanks in advance,

Michelle

 

 

PS: Please respond ASAP, this is rather urgent!!

Posted (edited)

Hi Michelle,

 

for me it is a little bit unclear what you want do do with

your code. You say "executing the class".... !?!?

 

My idea is: Try to make another project in which you

start again with a very easy version of that problem.

Threading can be a difficult thing and you must bear in mind,

that you cannot change a control (e.g. a textbox) from

another thread so easy. You HAVE TO USE BeginInvoke()

or Invoke() to make changes to the so called "UI-thread",

that is the thread, in which all your controls run.

 

Try to read some things in the net:

 

http://www.yoda.arachsys.com/csharp/multithreading.html

 

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetcomp/html/netcfmultithreadedapp.asp

 

 

Info from MSDN:

 

>>

Controls in Windows Forms are bound to a specific thread and are not thread safe. Therefore, if you are calling a control's method from a different thread, you must use one of the control's invoke methods to marshal the call to the proper thread. This property can be used to determine if you must call an invoke method, which can be useful if you do not know what thread owns a control. There are four methods on a control that are safe to call from any thread: Invoke, BeginInvoke, EndInvoke and CreateGraphics. For all other method calls, you should use one of these invoke methods when calling from a different thread.

 

Windows Forms uses the single-threaded apartment (STA) model because Windows Forms is based on native Win32 windows that are inherently apartment-threaded. The STA model implies that a window can be created on any thread, but it cannot switch threads once created, and all function calls to it must occur on its creation thread. Outside Windows Forms, classes in the .NET Framework use the free threading model.

<<

Edited by ToniMontana

Greetings,

 

Toni.

Posted

Hi Toni,

 

To explain what it is that I am trying to do...

 

I have a thread, call this ThreadClassRunner. When the ThreadClassRunner starts, it runs a particular function from a referenced class.

 

I also have a Timers.Timer that is to tick over to calculate the elapsed time taken for the function to complete - this can be up to several hours.

 

I have a textbox on my form that I want to update each time the timer.elapsed event fires so that the users are aware of a) the fact that the function is still running, and b) to inform them of how long the function is taking to run.

 

I know that the elapsed event continues to fire while the ThreadClassRunner is running because i a) created a console application that dumped output to the screen so I know what was happening, and this indicated that yes, the elapsed event continues to be handled correctly while the ThreadClassRunner is running. And, b) within my actual application, i ran a trace to the event log, and this also indicated that the elapsed event was correctly being handled while the ThreadClassRunner was running.

 

So, the timer is correctly handling the elapsed event. My problem is that the textbox (which i want the elapsed time to display in) is not refreshing each time the elapsed event is being handled.

 

I can't understand WHY this is happening, and I haven't been able to find to much info about how to fix it.

 

I don't understand how the textbox.Invoke() method works, and therefore, would really appreciate some more help with this.

 

Thanks.

 

 

BTW, I have been looking though the info that you provided links to, and it just seems to be help on the threading. I have the threading working - i just need to get the display working. Please remember that I do not create the timer on a thread, therefore, I would assume that the elapsed event is not being handled on a thread either. The only object in the application that is running on a thread is the class's function which runs on the ThreadClassRunner.

Posted

When you create a new thread, the main thread is still running. The timer does not and should not have it's own thread. Simple create a new thread for the worker function as you are and then create a loop that checks to see if that thread has finished, if not print the elapsed time to a label:

 

 

public Thread1 as Threading.Thread
private event FinishedLoading()
dim Timer as Timers.Timer

Public Sub New(byval parent as frmMain)
 Thread1 = new System.Threading.Thread(AddressOf CreateDDBatch)
 AddHandler FinishedLoading, AddressOf FinishedLoadingEH

 Timer = New System.Timers.Timer()
 Timer.Start()
 Thread1.Start()

 While (Thread1.Join(1000))

'this next line may be wrong, edit
  tbTimer.Text = "Hours: " + Cstr(Date.Now.Hours - Timer.Hours) + " Minutes: " + Cstr(Date.Now.Minutes - Timer.Minutes) + "   Seconds: " + Cstr(Date.Now.Seconds - Timer.Second)
 End While

End Sub

Private Sub CreateDDBatch()
 Dim DDProcessor as new clsID_DD_AutoProcessor(username, password)
 RaiseEvent FinishedLoading()
End Sub

Sub FinishedLoadingEH()
 Me.Cursor = Windows.Forms.Cursors.Default
 Me.btnClose.Enabled = True
End Sub

Posted

you guys are making this too hard. . .

 

look up 'Asynchronous Programming Design Pattern' in the help

 

use C#. . . vb blows

Joe Mamma

Amendment 4: The right of the people to be secure in their persons, houses, papers, and effects, against unreasonable searches and seizures, shall not be violated, and no warrants shall issue, but upon probable cause, supported by oath or affirmation, and particularly describing the place to be searched, and the persons or things to be seized.

Amendment 9: The enumeration in the Constitution, of certain rights, shall not be construed to deny or disparage others retained by the people.

Posted
you guys are making this too hard. . .

 

look up 'Asynchronous Programming Design Pattern' in the help

 

use C#. . . vb blows

 

use managed c++, c# blows

Posted
use managed c++' date=' c# blows[/quote']unless your working with clients who dont code

Joe Mamma

Amendment 4: The right of the people to be secure in their persons, houses, papers, and effects, against unreasonable searches and seizures, shall not be violated, and no warrants shall issue, but upon probable cause, supported by oath or affirmation, and particularly describing the place to be searched, and the persons or things to be seized.

Amendment 9: The enumeration in the Constitution, of certain rights, shall not be construed to deny or disparage others retained by the people.

Posted

Hi there...

 

Ok, so there have been a few bits of info here... but, I am a bit confused now.

 

I know what I need to do, and that is to get the textbox to display the elapsed time each time the timer.elapsed event is handled. Forget about the threading - I've got that working. I just need a piece of code to help me get the textbox to display the text properly.

 

Now, I am assuming from what I have read that I need to use the textbox.Invoke() method, but, I have no idea what to do with it!

I have to pass it a system.delegate, but what is it? You've seen my code above, should I pass it one of those methods?

 

Please help me with this - I really need to get this working.

 

 

Thanks,

Michelle

Posted

Ok... So, to probably make things worse... this is my new code. Bare in mind that this is still not making the textbox display the text each time the timer.elapsed event is handled, but I think i'm headed in the right direction - but I definately still need more help!!

 


   Dim myMainFrm As MADUSA_MainMenu
   Public Thread1 As Threading.Thread
   Dim MADConnector As clsMADConnObj.Connection
   Private Event FinishedLoading()

   Dim curtime As DateTime
   Dim Timer As Timers.Timer

   Dim t_StartTime As DateTime
   Dim t As TimeSpan

   Dim m_counter As Integer


   Public Sub New(ByVal parent As MADUSA_MainMenu)
       MyBase.New()
       myMainFrm = parent
       MADConnector = myMainFrm.GetMADConnector

       'This call is required by the Windows Form Designer.
       InitializeComponent()

       'Add any initialization after the InitializeComponent() call
       Thread1 = New System.Threading.Thread(AddressOf CreateDDBatch)
       Thread1.Name = "Create DD Batch Thread"
       AddHandler FinishedLoading, AddressOf FinishedLoadingEH
       t_StartTime = System.DateTime.Now
       Timer1Start()
       Thread1.Start()

   End Sub


   Private Sub CreateDDBatch()
       Dim DDProcessor As New clsID_DirectDebit_AutoProcessor.AutoProcessor(MADConnector, myMainFrm.GetUsername, myMainFrm.GetPassword)
       RaiseEvent FinishedLoading()
   End Sub

   Sub FinishedLoadingEH()
       Timer.Enabled = False
       Timer.Stop()

       Me.Cursor = Windows.Forms.Cursors.Default
       Me.btnClose.Enabled = True
       Thread1.Abort()

   End Sub

   Private Sub Timer1Start()
       Timer = New System.Timers.Timer(500)
       Timer.Enabled = True
       Timer.SynchronizingObject = myMainFrm
       AddHandler Timer.Elapsed, AddressOf TimerTick
       Timer.Enabled = True

       Timer.Start()
   End Sub

   Private Sub TimerTick(ByVal sender As System.Object, ByVal e As System.Timers.ElapsedEventArgs)
       Try
           Dim t_CurrentTime As DateTime = e.SignalTime
           Dim t_ElapsedTime As TimeSpan = t_CurrentTime.Subtract(t_StartTime)
           t = t_ElapsedTime

           UseDelegate()

       Catch ex As Exception
       End Try
   End Sub


   Delegate Sub UpdateTextbox(ByVal str As String)

   Private Function UseDelegate()
       Dim objUpdater As New Updater(Me)

       Dim objDelegator As UpdateTextbox
       objDelegator = New UpdateTextbox(AddressOf objUpdater.WriteSomething)

       objDelegator.Invoke(t.ToString)

   End Function

   Class Updater

       Dim sub_Parent As MADUSA_DirectDebitProcess_Timer

       Public Sub New(ByVal subp As MADUSA_DirectDebitProcess_Timer)
           sub_Parent = subp
       End Sub

       Public Sub WriteSomething(ByVal strToWrite As String)
           sub_Parent.tbTimer.Text = strToWrite
       End Sub
   End Class

 

Perhaps with this code, someone may be able to give me a hint??!!

 

Thanks again,

Michelle

Posted
I was able to get a sample program working' date=' I used a System.Windows.Forms.Timer[/quote']

 

Hi Diesel,

Could you please provide me with the code that you got to work?

Thanks,

Michelle

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...