0

I am trying to create little notification popups for my application and have created a new form that fades in and out and sits on top of my main form (seems to work okay).

My problem is that I have some code that sits inside a timer event that does some data checking every minute or so. Depending on the data results, I sometimes need to show a notification. However, it is causing me Cross-Thread errors (which is understandable), but I'm not sure how to get around it.

Example (in a nutshell) of what I am trying to do is:

Private Sub RefreshData(sender As Object, e As System.Timers.ElapsedEventArgs)
    Try
        MainRefreshTimer.Interval = GetInterval()
        MainRefreshTimer.Start()

        'Do some data checking here...
        If data returns true then
            Dim notify as New frmNewNotification("Some Text", 10) '<== Show some text for 10 seconds then close the form automatically
            notify.Show() '<== Cross Thread Error occurs from this
        End If
    ...

End Sub
Riples
  • 1,167
  • 2
  • 21
  • 54
  • Do **not** use a System.Timers.Timer, many things wrong with it. You don't need anything more than the Timer you find back in the toolbox. – Hans Passant Apr 16 '15 at 08:36
  • @HansPassant I suppose you're my downvoter. I use that 'answer' on my Threads. What the main reason for -1? Not to advise of using system.windows.forms.timer? Really want to know. No hard feelings :) – Morcilla de Arroz Apr 16 '15 at 10:00
  • It was not me. But surely *somebody* was horrified at you giving this user a gun to shoot his leg off. Setting Control.CheckForIllegalCrossThreadCalls to *false* is a horrible workaround, the programmer loses all hope of diagnosing the occasional deadlock he'll get. It is completely undebuggable. – Hans Passant Apr 16 '15 at 10:33
  • @HansPassant Can you see anything wrong with the `InvokeRequired` method, as that's what I implemented and it seems to be working fine. I did steer clear of the `CheckForIllegalCrossThreadCalls = False` as I already knew that was a 'loaded gun' so to speak. :) – Riples Apr 16 '15 at 11:54
  • There just completely isn't any point in writing that code. It is not better than using a System.Windows.Forms.Timer. It is in fact worse, much worse. The threading race you get when the user closes the window but the timer keeps on ticking, or has scheduled a tick, will crash your program randomly. Not often enough to find out that the code is broken. – Hans Passant Apr 16 '15 at 12:01
  • @HansPassant Thanks Hans for the reply. Would it be possible to post a different solution then? Or is that becoming off-topic? I am just eager to get a solution to this issue. Thanks – Riples Apr 16 '15 at 12:18
  • I don't really understand why somebody has to post to inspire you to use the correct Timer class. – Hans Passant Apr 16 '15 at 12:29
  • @HansPassant Okay, I'm confused! You said I shouldn't use the System.Timers.Timer in one post, then another saying it's not better than using the System.Windows.Forms.Timer. I was only asking you to post an example if you felt that I shouldn't use a timer at all and there was a better method. I will change my code to a System.Windows.Forms.Timer. Thanks – Riples Apr 16 '15 at 12:40
  • @Riples This is that he is talking about http://stackoverflow.com/questions/1416803/system-timers-timer-vs-system-threading-timer – Morcilla de Arroz Apr 16 '15 at 14:18
  • @HansPassant I only answered the question 'as is'. But Riples. really he's right about System.Timers.Timer. My anwer it's ok for something like a controlled Threading.Thread. But *System.Timers.Timer*, has issues discussede here http://stackoverflow.com/questions/1416803/system-timers-timer-vs-system-threading-timer. Maybe you can simply paste a Forms.Timer, and play with Tick Event. I'll mantain my answer for future readers. Regards! – Morcilla de Arroz Apr 17 '15 at 06:35

1 Answers1

-1

I would try one of this ideas:

Shorcut: Put this in your Form_Load

Control.CheckForIllegalCrossThreadCalls = False 

Or, better, something like:

Private Sub delRefreshData(data as Object)
  If Me.InvokeRequired Then
    ' Invoke(New MethodInvoker(AddressOf delRefreshData)) ' no params
    Invoke(New MethodInvoker(Sub() delRefreshData(data)))
  Else
    'Do some data checking here...
      If data returns true then
       Dim notify as New frmNewNotification("Some Text", 10) 
       notify.Show() '
      End If
  End if

Using InvokeRequired vs control.InvokeRequired

Edited: To avoid in future be blamed for that Shorcut, I have to say that Control.CheckForIllegalCrossThreadCalls isn't a good advice/solution, as is discussed here:

Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on

Community
  • 1
  • 1
Morcilla de Arroz
  • 2,104
  • 22
  • 29
  • I couldn't use the `MethodInvoker` because it wouldn't accept any values and the RefreshData routine has `sender As Object, e As System.Timers.ElapsedEventArgs`. – Riples Apr 16 '15 at 07:23
  • Changing your example to `Invoke(New MethodInvoker(Sub() RefreshData(Me, Nothing)))` seems to be working for me. I will keep testing... – Riples Apr 16 '15 at 07:42
  • oh! sure, it's wrong, because it's "Private SUB" :) I was wrong. Edited. – Morcilla de Arroz Apr 16 '15 at 07:46