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. .NET (Core and Framework)
  4. Semi-background task on UI thread

Semi-background task on UI thread

Scheduled Pinned Locked Moved .NET (Core and Framework)
questiondesignjsonannouncement
11 Posts 4 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.
  • S Offline
    S Offline
    supercat9
    wrote on last edited by
    #1

    What is the best way to handle a task which must be performed on the UI thread, but which may take awhile to complete (e.g. a slow control update or redraw)? One approach would be to do part of the task and then BeginInvoke a routine which will do the rest (possibly by itself doing part and using BeginInvoke again). That approach, however, could end up wasting a lot of CPU time handling the BeginInvoke operations in cases where there isn't anything else for the UI thread to be doing and the tasks could have been run to completion. Is there any good way to say "Run this code if there isn't anything better for the UI thread to do", and then (within that code) ask "Has anything else come up the UI thread should be doing"? Alternatively, are there any tricks that would allow a control to be drawn within its own thread? I would expect interaction between the control and the rest of the form would have to be handled on the form's UI thread, and the control would have to have a means of queueing things like resize events from the UI thread and dealing with them sensibly, but if a control would otherwise take a little time to render being able to handle the rendering on its own thread would be helpful.

    J S 2 Replies Last reply
    0
    • S supercat9

      What is the best way to handle a task which must be performed on the UI thread, but which may take awhile to complete (e.g. a slow control update or redraw)? One approach would be to do part of the task and then BeginInvoke a routine which will do the rest (possibly by itself doing part and using BeginInvoke again). That approach, however, could end up wasting a lot of CPU time handling the BeginInvoke operations in cases where there isn't anything else for the UI thread to be doing and the tasks could have been run to completion. Is there any good way to say "Run this code if there isn't anything better for the UI thread to do", and then (within that code) ask "Has anything else come up the UI thread should be doing"? Alternatively, are there any tricks that would allow a control to be drawn within its own thread? I would expect interaction between the control and the rest of the form would have to be handled on the form's UI thread, and the control would have to have a means of queueing things like resize events from the UI thread and dealing with them sensibly, but if a control would otherwise take a little time to render being able to handle the rendering on its own thread would be helpful.

      J Offline
      J Offline
      Jon Rista
      wrote on last edited by
      #2

      Could you explain why this has to be run in the UI thread? The purpose of the UI thread is very specific...to manage the UI. Most of the time application logic can be run synchronously in the UI thread because it only takes moments to complete. However, any long-running processes should be separated into application logic and UI logic, and the application logic should be run in a background thread. You have many options for keeping a UI in sync with work that is being done in the background. You can use Control.Invoke to invoke operations in the UI thread from your background thread. You can use a BackgroundWorker with progress reporting on to periodically report progress from your background thread with user data for each event. You can execute methods asynchronously with delegates or use the ThreadPool and worker items to manage background tasks. The .NET framework also offers a lot of thread synchronization features, rooted in the WaitHandle class. You can use WaitHandles to create signaling between threads, without having to constantly start and stop each worker with explicit calls to BeginInvoke or the like.

      S 1 Reply Last reply
      0
      • J Jon Rista

        Could you explain why this has to be run in the UI thread? The purpose of the UI thread is very specific...to manage the UI. Most of the time application logic can be run synchronously in the UI thread because it only takes moments to complete. However, any long-running processes should be separated into application logic and UI logic, and the application logic should be run in a background thread. You have many options for keeping a UI in sync with work that is being done in the background. You can use Control.Invoke to invoke operations in the UI thread from your background thread. You can use a BackgroundWorker with progress reporting on to periodically report progress from your background thread with user data for each event. You can execute methods asynchronously with delegates or use the ThreadPool and worker items to manage background tasks. The .NET framework also offers a lot of thread synchronization features, rooted in the WaitHandle class. You can use WaitHandles to create signaling between threads, without having to constantly start and stop each worker with explicit calls to BeginInvoke or the like.

        S Offline
        S Offline
        supercat9
        wrote on last edited by
        #3

        Sometimes updating or redrawing a control can take a non-trivial amount of time. Not necessarily a huge amount of time, but non-trivial (say, 100ms). Control redrawing has to be done on the UI thread, but blocking the UI thread for 100ms at a time can make the application feel "chunky". It would seem better to allow other things to take priority over the control redrawing when there are other things to be done. In some cases the right approach would be to have a different thread draw the control contents in an off-screen bitmap, and then make that bitmap available to the UI thread. Such an approach would not be without its own drawbacks, however. Having each control create a separate thread for processing would be wasteful. Having all the controls of a class share a thread might be better, but unless the controls contain logic to subdivide their work a slow control could delay action on the rest. Even in the absence threading issues, processing off-screen bitmaps and copying them is generally slower than drawing directly to the screen. Incidentally, what should be the normal pattern for controls which allow actions that may take awhile to complete (e.g. setting the RichTextBox's .rtf property)? Microsoft's controls require that most actions be performed on the UI thread, and they'll block the UI thread for as long as the actions take, but that seems rather icky. I'd like to design any of my own controls to avoid such blocking behavior in the UI thread.

        J N 2 Replies Last reply
        0
        • S supercat9

          Sometimes updating or redrawing a control can take a non-trivial amount of time. Not necessarily a huge amount of time, but non-trivial (say, 100ms). Control redrawing has to be done on the UI thread, but blocking the UI thread for 100ms at a time can make the application feel "chunky". It would seem better to allow other things to take priority over the control redrawing when there are other things to be done. In some cases the right approach would be to have a different thread draw the control contents in an off-screen bitmap, and then make that bitmap available to the UI thread. Such an approach would not be without its own drawbacks, however. Having each control create a separate thread for processing would be wasteful. Having all the controls of a class share a thread might be better, but unless the controls contain logic to subdivide their work a slow control could delay action on the rest. Even in the absence threading issues, processing off-screen bitmaps and copying them is generally slower than drawing directly to the screen. Incidentally, what should be the normal pattern for controls which allow actions that may take awhile to complete (e.g. setting the RichTextBox's .rtf property)? Microsoft's controls require that most actions be performed on the UI thread, and they'll block the UI thread for as long as the actions take, but that seems rather icky. I'd like to design any of my own controls to avoid such blocking behavior in the UI thread.

          J Offline
          J Offline
          Jon Rista
          wrote on last edited by
          #4

          Given the nature of how UI works in a classic Forms app, I am not sure that drawing on an alternate thread is really feasible. I'm not even sure its desirable, either. There is a difference between a responsive UI, and a UI that is usable but not completely drawn. As a user, I would expect that when my UI is redrawing (if that redrawing takes a while) that it fully completes that drawing before it returns to me and allows me to edit content. If I am allowed to edit content in an incomplete UI...I would feel that the program is just asking, if not begging, me to make an edit on stale or incomplete content. If you need a highly responsive UI, you might want to look to WPF. Windows Forms is bound by the classic and somewhat legacy way that UI works in Windows...based on a message loop and blocking redraw actions. WPF, on the other hand, is a very modern system that allows drawing activities to be fully hardware accelerated. You are even free to write custom shaders to render your controls, or render effects on your controls. Given that its hardware accelerated, lag time should be well below that 100ms mark unless your processing significantly more data than is actually visible in the UI (i.e. the RichTextBox control, which processes the whole .rtf before rendering the viewport....it should just process the part of the RTF that is visible in the viewport).

          S 1 Reply Last reply
          0
          • J Jon Rista

            Given the nature of how UI works in a classic Forms app, I am not sure that drawing on an alternate thread is really feasible. I'm not even sure its desirable, either. There is a difference between a responsive UI, and a UI that is usable but not completely drawn. As a user, I would expect that when my UI is redrawing (if that redrawing takes a while) that it fully completes that drawing before it returns to me and allows me to edit content. If I am allowed to edit content in an incomplete UI...I would feel that the program is just asking, if not begging, me to make an edit on stale or incomplete content. If you need a highly responsive UI, you might want to look to WPF. Windows Forms is bound by the classic and somewhat legacy way that UI works in Windows...based on a message loop and blocking redraw actions. WPF, on the other hand, is a very modern system that allows drawing activities to be fully hardware accelerated. You are even free to write custom shaders to render your controls, or render effects on your controls. Given that its hardware accelerated, lag time should be well below that 100ms mark unless your processing significantly more data than is actually visible in the UI (i.e. the RichTextBox control, which processes the whole .rtf before rendering the viewport....it should just process the part of the RTF that is visible in the viewport).

            S Offline
            S Offline
            supercat9
            wrote on last edited by
            #5

            As a user, I would expect that when my UI is redrawing (if that redrawing takes a while) that it fully completes that drawing before it returns to me and allows me to edit content. If one is using an MDI application, all child windows of a form must be drawn by the same thread. While the system should ensure that anything the user thinks he's editing is actually there, that doesn't imply that a user should be forbidden from editing anything (even in other windows!) unless everything is current. There are many applications that operate on the general principle I describe. Google Maps, for example, allows the user to pan around a map without having to wait for everything to be updated. I hardly think that service would be improved by requiring that the user wait for each screen update to complete before being allowed to pan or zoom, or even close the application for that matter. Of course, Google Maps happens to do updates in nice big chunks because that's how its data-transfer facilities are set up, but that doesn't mean that's the best approach for applications where data is locally available but may take a little time to render.

            J 1 Reply Last reply
            0
            • S supercat9

              Sometimes updating or redrawing a control can take a non-trivial amount of time. Not necessarily a huge amount of time, but non-trivial (say, 100ms). Control redrawing has to be done on the UI thread, but blocking the UI thread for 100ms at a time can make the application feel "chunky". It would seem better to allow other things to take priority over the control redrawing when there are other things to be done. In some cases the right approach would be to have a different thread draw the control contents in an off-screen bitmap, and then make that bitmap available to the UI thread. Such an approach would not be without its own drawbacks, however. Having each control create a separate thread for processing would be wasteful. Having all the controls of a class share a thread might be better, but unless the controls contain logic to subdivide their work a slow control could delay action on the rest. Even in the absence threading issues, processing off-screen bitmaps and copying them is generally slower than drawing directly to the screen. Incidentally, what should be the normal pattern for controls which allow actions that may take awhile to complete (e.g. setting the RichTextBox's .rtf property)? Microsoft's controls require that most actions be performed on the UI thread, and they'll block the UI thread for as long as the actions take, but that seems rather icky. I'd like to design any of my own controls to avoid such blocking behavior in the UI thread.

              N Offline
              N Offline
              N a v a n e e t h
              wrote on last edited by
              #6

              What type of control are you talking about? Some controls provide methods like BeginUpdate which can be used to prevent control from drawing until you call EndUpdate.

              supercat9 wrote:

              Incidentally, what should be the normal pattern for controls which allow actions that may take awhile to complete (e.g. setting the RichTextBox's .rtf property)?

              You can use a worker thread to load the data into memory and let UI thread read from the memory to fill the control. But still you will see some delay if the data is too heavy and I don't think that there is a method to avoid this. :)

              Navaneeth How to use google | Ask smart questions

              S 1 Reply Last reply
              0
              • N N a v a n e e t h

                What type of control are you talking about? Some controls provide methods like BeginUpdate which can be used to prevent control from drawing until you call EndUpdate.

                supercat9 wrote:

                Incidentally, what should be the normal pattern for controls which allow actions that may take awhile to complete (e.g. setting the RichTextBox's .rtf property)?

                You can use a worker thread to load the data into memory and let UI thread read from the memory to fill the control. But still you will see some delay if the data is too heavy and I don't think that there is a method to avoid this. :)

                Navaneeth How to use google | Ask smart questions

                S Offline
                S Offline
                supercat9
                wrote on last edited by
                #7

                In the particular immediate case, I'm thinking about a control that's somewhat like an enhanced ListBox which allows for the possibility of a list item changing height. When the width of the control is changed, its items get a chance to redetermine their height. My plan is to do this first for the items on the screen, and then for everything else; all items would have to be measured to set the scroll bar accurately, but I wouldn't want to hold up the entire UI thread for that. If the control were an opaque class, it might make sense for the measurement to be done in a background thread. Since it is not, however, it would seem like very poor style to have a background thread call the list contents' measure-item methods which may not be expecting invocation outside the UI thread.

                1 Reply Last reply
                0
                • S supercat9

                  What is the best way to handle a task which must be performed on the UI thread, but which may take awhile to complete (e.g. a slow control update or redraw)? One approach would be to do part of the task and then BeginInvoke a routine which will do the rest (possibly by itself doing part and using BeginInvoke again). That approach, however, could end up wasting a lot of CPU time handling the BeginInvoke operations in cases where there isn't anything else for the UI thread to be doing and the tasks could have been run to completion. Is there any good way to say "Run this code if there isn't anything better for the UI thread to do", and then (within that code) ask "Has anything else come up the UI thread should be doing"? Alternatively, are there any tricks that would allow a control to be drawn within its own thread? I would expect interaction between the control and the rest of the form would have to be handled on the form's UI thread, and the control would have to have a means of queueing things like resize events from the UI thread and dealing with them sensibly, but if a control would otherwise take a little time to render being able to handle the rendering on its own thread would be helpful.

                  S Offline
                  S Offline
                  S Senthil Kumar
                  wrote on last edited by
                  #8

                  At worst, you could call Application.DoEvents to run any pending UI operations. Beware of issues like reentrancy though.

                  Regards Senthil [MVP - Visual C#] _____________________________ My Home Page |My Blog | My Articles | My Flickr | WinMacro

                  S 1 Reply Last reply
                  0
                  • S supercat9

                    As a user, I would expect that when my UI is redrawing (if that redrawing takes a while) that it fully completes that drawing before it returns to me and allows me to edit content. If one is using an MDI application, all child windows of a form must be drawn by the same thread. While the system should ensure that anything the user thinks he's editing is actually there, that doesn't imply that a user should be forbidden from editing anything (even in other windows!) unless everything is current. There are many applications that operate on the general principle I describe. Google Maps, for example, allows the user to pan around a map without having to wait for everything to be updated. I hardly think that service would be improved by requiring that the user wait for each screen update to complete before being allowed to pan or zoom, or even close the application for that matter. Of course, Google Maps happens to do updates in nice big chunks because that's how its data-transfer facilities are set up, but that doesn't mean that's the best approach for applications where data is locally available but may take a little time to render.

                    J Offline
                    J Offline
                    Jon Rista
                    wrote on last edited by
                    #9

                    The fundamental nature of Google maps is a bit different...your only viewing, not editing. In that case, sure, delayed updates work fine, as there is no chance the user will modify incomplete information.

                    S 1 Reply Last reply
                    0
                    • S S Senthil Kumar

                      At worst, you could call Application.DoEvents to run any pending UI operations. Beware of issues like reentrancy though.

                      Regards Senthil [MVP - Visual C#] _____________________________ My Home Page |My Blog | My Articles | My Flickr | WinMacro

                      S Offline
                      S Offline
                      supercat9
                      wrote on last edited by
                      #10

                      I suppose Application.DoEvents might not be totally evil in that circumstance; maintain a flag to ignore recursive calls and the rest of the UI should be able to function while the updates are completed. It would be nicer if there were a version of Application.DoEvents that would only handle certain events while ignoring others, but I don't know of any such beast.

                      1 Reply Last reply
                      0
                      • J Jon Rista

                        The fundamental nature of Google maps is a bit different...your only viewing, not editing. In that case, sure, delayed updates work fine, as there is no chance the user will modify incomplete information.

                        S Offline
                        S Offline
                        supercat9
                        wrote on last edited by
                        #11

                        Many of the controls I design are essentially view-only, and I expect that's not particularly unusual. Even edit controls, however, shouldn't IMHO ever block the UI thread for more than a small fraction of a second. If the control needs to do something that may take awhile, it should allow the UI thread to run in the mean time even if the control itself shows a "busy" indicator and is not functional. A recent article seems to deal with this subject, so I'll have to see what I can make of that.

                        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