-2

i have been searching online and cant seem to find an appropriate fix for my error: Cross-thread operation not valid: Control 'Form1' accessed from a thread other than the thread it was created on.

I looked onto but cant figure out how i invoke my size change?

My code which works some times and the other throws the above code is:

'Handler to handle screen resizes! (Tablet being flipped etc...)
Private Sub TouchRadio_Resize(sender As Object, e As EventArgs) Handles Me.Resize
    Dim thread As New Thread(AddressOf resizescreen)
    thread.Start()
End Sub

Public Sub resizescreen()
    System.Threading.Thread.Sleep(1)
    For index As Integer = 1 To 50000
        If Screen.PrimaryScreen.Bounds.Width = (Screen.PrimaryScreen.Bounds.Width + 17) Then
            Exit For
        End If
        Dim screenWidth As Integer = Screen.PrimaryScreen.Bounds.Width
        screenWidth = (screenWidth + 17)
        Dim screenHeight As Integer = Screen.PrimaryScreen.Bounds.Height
        Me.Size = New System.Drawing.Size(screenWidth, screenHeight) 'Here it errors at
        GeckoWebBrowser1.Size = New System.Drawing.Size(screenWidth, screenHeight)
        Me.Location = New Point(0, 0)
    Next
End Sub
William
  • 1,009
  • 15
  • 41
  • It seems that the method could be greatly reduced in complexity and redundancy. Must `Me.Location = New Point(0, 0)` be called 50k times? I would change `If Screen.PrimaryScreen.Bounds.Width = (Screen.PrimaryScreen.Bounds.Width + 17)` from equality to >= – djv Sep 21 '17 at 19:27

1 Answers1

1

You can use this little helper.

Public Shared Sub InvokeIfRequired(c As Control, action As Action(Of Control))
    If c.InvokeRequired Then
        c.Invoke(New Action(Sub() action(c)))
    Else
        action(c)
    End If
End Sub

and put your stuff in it:

    InvokeIfRequired(Me.Size, 
       Sub()
            For index As Integer = 1 To 50000
                If Screen.PrimaryScreen.Bounds.Width = (Screen.PrimaryScreen.Bounds.Width + 17) Then
                    Exit For
                End If
                Dim screenWidth As Integer = Screen.PrimaryScreen.Bounds.Width
                screenWidth = (screenWidth + 17)
                Dim screenHeight As Integer = Screen.PrimaryScreen.Bounds.Height
                Me.Size = New System.Drawing.Size(screenWidth, screenHeight) 'Here it errors at
                GeckoWebBrowser1.Size = New System.Drawing.Size(screenWidth, screenHeight)
                Me.Location = New Point(0, 0)
            Next
        End Sub)

This way, it gets invoked if required.


UPDATE

I just want to point out, that some comments are very helpful. @djv describes a nice extension and @Visual Vincent points out, that you should invoke as little as possible.

Marius
  • 369
  • 1
  • 10
  • 1
    Wrapping the entire loop in `InvokeIfRequired` totally defeats the purpose of multithreading... Only invoke the lines that actually access the UI. -- Also, there's no point in using an `Action(Of Control)` unless you plan on retrieving the invoker control inside the invoked method (which you don't, at the moment). Using a regular `Action` is enough. – Visual Vincent Sep 21 '17 at 17:24
  • 1
    The method is better written as: ` Public Sub InvokeIfRequired(control As Control, action As MethodInvoker)` `If control.InvokeRequired Then control.Invoke(action) Else action()` `End Sub` – djv Sep 21 '17 at 19:17
  • @VisualVincent you are partly correct. Invoke itself is costly. So if the Loop calls 50000 invokes it might be even slower then one big invoke. But in general you are correct. Do small invokes. – Marius Sep 22 '17 at 08:58
  • It's not _that_ costly. I've used it in many different kinds of threads without a noticable decrease of performance. Though if you are worried about the execution time just switch to `BeginInvoke()`. – Visual Vincent Sep 22 '17 at 09:07
  • Marius you effectively negate the Thread by invoking all the code on the UI. But it's unclear why OP needs to loop 50k times anyway. Btw in addition to @VisualVincent comment about your your version of InvokeIfRequired's second argument, it has a Control as 1st argument, while you have passed Control.Size. – djv Sep 22 '17 at 14:09