Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. Visual Basic
  4. Click a main thread button from a background thread

Click a main thread button from a background thread

Scheduled Pinned Locked Moved Visual Basic
questionhelptutorial
6 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • T Offline
    T Offline
    treddie
    wrote on last edited by
    #1

    Hi all. I have a curious question. I know how to do this the "official" way, but I want to try to do it backwards, and it seems it should be possible. But I am new to delegates. I have read a few articles on how to get a button to respond to mouse clicks when the main thread is super busy running some really long task. The methods always revolved around putting that task in a background thread, so that the form was not held up in any way in terms of handling events. I understand these methods fairly well right now. But I am curious if the reverse is possible? Can the main thread be stuck in the middle of some long task, and can its form have a button that can respond to a delegate in a background task. All the button does is set/reset a public flag. If the button could respond, the flag would get valued, and that would impact what the main thread is doing. Everything I have tried has failed, because I do not understand how to use a delegate that can support a user-interactive feature, like a button click. I have a kludge idea that might work, but it is a bit clunky. It would involve a transparent second form on a separate thread that overlays the main thread's form, and has that button on it in the exact position where it WOULD be, if it had been on the main thread's form. So to the user, it just looks like another button on the main form. But I don't like the idea because it has a clunk factor of ten. :) All that work for a single button, especially since if I want to resize or move the main form, the second form has to move along with it. Just plain messy. So it just seems that some sort of delegate approach should work to avoid all that mess. Thanks to anyone who can offer advice on a reverse-logic idea that may be leaving a bad taste in your mouth.

    B G 2 Replies Last reply
    0
    • T treddie

      Hi all. I have a curious question. I know how to do this the "official" way, but I want to try to do it backwards, and it seems it should be possible. But I am new to delegates. I have read a few articles on how to get a button to respond to mouse clicks when the main thread is super busy running some really long task. The methods always revolved around putting that task in a background thread, so that the form was not held up in any way in terms of handling events. I understand these methods fairly well right now. But I am curious if the reverse is possible? Can the main thread be stuck in the middle of some long task, and can its form have a button that can respond to a delegate in a background task. All the button does is set/reset a public flag. If the button could respond, the flag would get valued, and that would impact what the main thread is doing. Everything I have tried has failed, because I do not understand how to use a delegate that can support a user-interactive feature, like a button click. I have a kludge idea that might work, but it is a bit clunky. It would involve a transparent second form on a separate thread that overlays the main thread's form, and has that button on it in the exact position where it WOULD be, if it had been on the main thread's form. So to the user, it just looks like another button on the main form. But I don't like the idea because it has a clunk factor of ten. :) All that work for a single button, especially since if I want to resize or move the main form, the second form has to move along with it. Just plain messy. So it just seems that some sort of delegate approach should work to avoid all that mess. Thanks to anyone who can offer advice on a reverse-logic idea that may be leaving a bad taste in your mouth.

      B Offline
      B Offline
      Bernhard Hiller
      wrote on last edited by
      #2

      A button has a PerformClick method - if he button is public, you could call that. But actually that's not the way to do it. In the event handler of the button click event, you call a method to do the things you want to do on that button click. If that method is public, you could directly call it. However, if UI elements are accessed, you should check for InvokeRequired.

      T 1 Reply Last reply
      0
      • T treddie

        Hi all. I have a curious question. I know how to do this the "official" way, but I want to try to do it backwards, and it seems it should be possible. But I am new to delegates. I have read a few articles on how to get a button to respond to mouse clicks when the main thread is super busy running some really long task. The methods always revolved around putting that task in a background thread, so that the form was not held up in any way in terms of handling events. I understand these methods fairly well right now. But I am curious if the reverse is possible? Can the main thread be stuck in the middle of some long task, and can its form have a button that can respond to a delegate in a background task. All the button does is set/reset a public flag. If the button could respond, the flag would get valued, and that would impact what the main thread is doing. Everything I have tried has failed, because I do not understand how to use a delegate that can support a user-interactive feature, like a button click. I have a kludge idea that might work, but it is a bit clunky. It would involve a transparent second form on a separate thread that overlays the main thread's form, and has that button on it in the exact position where it WOULD be, if it had been on the main thread's form. So to the user, it just looks like another button on the main form. But I don't like the idea because it has a clunk factor of ten. :) All that work for a single button, especially since if I want to resize or move the main form, the second form has to move along with it. Just plain messy. So it just seems that some sort of delegate approach should work to avoid all that mess. Thanks to anyone who can offer advice on a reverse-logic idea that may be leaving a bad taste in your mouth.

        G Offline
        G Offline
        GuyThiebaut
        wrote on last edited by
        #3

        Set up an extension method:

        Module Extensions

             \_
            Sub SynchronisedInvoke(synchMe As ISynchronizeInvoke, action As Action)
        
                If Not synchMe.InvokeRequired Then
        
                    action()
        
                Else
        
                    synchMe.Invoke(action, New Object() {})
        
                End If
        
            End Sub
        
        End Module
        

        Then you can call the btnClickety method(which is fired when the button is clicked) in this manner:

        btnClickety.SynchronisedInvoke(Sub() btnClickety)

        “That which can be asserted without evidence, can be dismissed without evidence.”

        ― Christopher Hitchens

        T 1 Reply Last reply
        0
        • B Bernhard Hiller

          A button has a PerformClick method - if he button is public, you could call that. But actually that's not the way to do it. In the event handler of the button click event, you call a method to do the things you want to do on that button click. If that method is public, you could directly call it. However, if UI elements are accessed, you should check for InvokeRequired.

          T Offline
          T Offline
          treddie
          wrote on last edited by
          #4

          Bernhard Hiller wrote:

          However, if UI elements are accessed, you should check for InvokeRequired.

          That's exactly where my problem is, I think. I am doing InvokeRequired, but am getting screwed up somewhere. Now, I also just got an error back at one point saying that delegates cannot handle events. I am assuming that means you can pass arguments to a control, but if you need to fire one of its events, like a button click, a delegate won't work. Not sure about that, though. At any rate, here is my code so far. I took the guts from a demo and attempted to modify it to do the reverse of what it did originally...Run some really long task as a background thread and let the controls be free for use in the main thread. This experiment is attempting to do the opposite...Run the task in the main thread, and work the form's button via a background task. It doesn't toggle the Pause/Continue state just yet...At this point, I was just trying to get the button to respond to a simple click. Also, the Run method at the very bottom does the Invoke, but it causes the program launch to hang during form load. I figured I might run into problems there, since I may be trying something impossible with a delegate, or I've just got everything set up wrong.

          Imports System.Threading
          'Imports System

          Public Class Form1

          '--------------------------------------------------------------------------------------
          'Background thread setup for the Pause/Continue button:

          'Define a delegate type for the form's Pause_Continue_cmd button:
          Private Delegate Sub Pause_Continue_cmd_ClickDelegateType(_
          ByVal sender As System.Object, _
          ByVal e As System.EventArgs)

          'Declare a delegate button to point to the form's Pause_Continue_cmd button:
          Private Pause_Continue_cmd_ClickDelegate As _
          Pause_Continue_cmd_ClickDelegateType

          Private BG_Thread As Thread

          'The main thread as "owner" of Form1 (and its controls will provide the actual
          'button clicks for the Pause_Continue_cmd button, because the background thread
          'cannot access the form's controls directly.
          '--------------------------------------------------------------------------------------

          Private Sub Form1_Load(ByVal sender As System.Object, _
          ByVal e As System.EventArgs) _
          Handles MyBase.Load

          FormIsLoadingFlag = 1
              Threading.Thread.CurrentThread.Name =
          
          1 Reply Last reply
          0
          • G GuyThiebaut

            Set up an extension method:

            Module Extensions

                 \_
                Sub SynchronisedInvoke(synchMe As ISynchronizeInvoke, action As Action)
            
                    If Not synchMe.InvokeRequired Then
            
                        action()
            
                    Else
            
                        synchMe.Invoke(action, New Object() {})
            
                    End If
            
                End Sub
            
            End Module
            

            Then you can call the btnClickety method(which is fired when the button is clicked) in this manner:

            btnClickety.SynchronisedInvoke(Sub() btnClickety)

            “That which can be asserted without evidence, can be dismissed without evidence.”

            ― Christopher Hitchens

            T Offline
            T Offline
            treddie
            wrote on last edited by
            #5

            I'll give it a try. For now, I have to get to bed...It's almost 3am! I will report back. Update: I have some homework to do here. I am unfamiliar with action data types.

            T 1 Reply Last reply
            0
            • T treddie

              I'll give it a try. For now, I have to get to bed...It's almost 3am! I will report back. Update: I have some homework to do here. I am unfamiliar with action data types.

              T Offline
              T Offline
              treddie
              wrote on last edited by
              #6

              After studying this for a while, It seems that setting up an action and an extension is really just a simplification of doing an explicit delegate and attaching a method to it. So my existing code should do the same thing, then, except that I think I have the guts wrong in the Run() procedure and other places. Unless my assumptions are wrong, it seems that before I jump into Actions and Extensions, I need to understand the explicit delegate approach. UPDATE: I am running your extensions idea, and I can get the b/g thread to run a task, but I am still not getting the button to respond, once I have the main thread caught in a long task. I was thinking that part of my problem is that I don't think the background thread is monitoring mouse behavior. When I start the program, the Form_Load sub starts the background thread, which gets the delegate going and the Run() sub is called. Even if I make the Run() procedure a continuous loop, it is going directly to the button click procedure every time, regardless of whether or not I have clicked the button. That part seems to make sense...Why would I WANT it to keep looping through the click event?! So I think I have one choice in that respect: 1. Have the Run() procedure monitor mouse behavior continuously, and when any button is clicked, check sender and only go to the Pause_Continue button click handler when it was the button in question. A monitor like that sounds like some sort of event listener. Not sure how to do that without some API functions. UPDATE 2: After researching some more, it looks like maybe something involving WithEvents could work. UPDATE 3: Now it looks more like AddHandler/RemoveHandler is the way to go.

              1 Reply Last reply
              0
              Reply
              • Reply as topic
              Log in to reply
              • Oldest to Newest
              • Newest to Oldest
              • Most Votes


              • Login

              • Don't have an account? Register

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • World
              • Users
              • Groups