In C#, wait on the mainthread while continuing to process UI updates? (.NET 2.0 CF)

前端 未结 10 2175
梦谈多话
梦谈多话 2020-12-18 11:49

I want to otherwise block code execution on the main thread while still allowing UI changes to be displayed.

I tried to come up with a simplified example version of

相关标签:
10条回答
  • 2020-12-18 12:15

    You want to use the "BackgroundWorker" class, which will take most of this pain out of this for you.. but as mentioned before, you'll also want to structure it so that the main thread is updating the UI and the worker is doing the heavy lifting.

    0 讨论(0)
  • 2020-12-18 12:15

    It is easyer then you might think.

    Suggestion: when you need a thread to perform some occasional work, get it from the threadpool, so you will not need strange/error prone recycling code.

    When you want something on another thread to update your UI, you just need a reference to the form and to call Form.Invoke passing the UI code you want the main thread to execute; it's a best pactice, in an event, to release the UI thread as soon as possible.

    Ie:

    private void button1_Click(object sender, EventArgs e)
    {
        // this is the UI thread
    
        ThreadPool.QueueUserWorkItem(delegate(object state)
        {
            // this is the background thread
            // get the job done
            Thread.Sleep(5000);
            int result = 2 + 2;
    
            // next call is to the Invoke method of the form
            this.Invoke(new Action<int>(delegate(int res)
            {
                // this is the UI thread
                // update it!
                label1.Text = res.ToString();
            }), result);
        });
    }
    

    Hope this helps you:)

    EDIT: I am sorry, I didn't read the "blocking user workflow" part.

    WindowsForms is not designed to do that, blocking the main thread is BAD (it handles the messages from the OS).

    You don't have to block the user workflow via freezing a form (which would then be considered "Not Responding" by windows), the way to block user workflow is by disabling any control you want (with the Invoke method above if from another thread), even the entire form!!

    0 讨论(0)
  • 2020-12-18 12:18

    I went with something I haven't seen posted yet which is to use MessageQueues.

    • The MainThread blocks while waiting for the next message on a queue.
    • The background thread posts different types of messages to the MessageQueue.
    • Some of the message types signal the MainThread to update UI elements.
    • Of course, there is a message to tell the MainThread to stop blocking and waiting for messages.

    Seems over the top considering the windows message loop already exists somewhere, but it works.

    0 讨论(0)
  • 2020-12-18 12:21

    If you could adjust your code so that you set a flag once a process has begun and then check that in the UI before you start an additional operation I think you'd have a much easier time coding this. I would create a delegate that could be called from the thread in the threadpool or user created thread to update on progress in the UI. Once the background process has been completed switch the flag and now normal UI operations can continue. The only caveat you need to be aware of is that when you update UI components you must do it on the thread they were created on, the main/UI thread. In order to accomplish this you can call the Invoke() method on any control that lives on that thread and pass it the delegate and parameters you need to call it.

    Here's a link to a tutorial I wrote some time ago about how to use Control.Invoke():

    http://xsdev.net/tutorials/pop3fetcher/

    0 讨论(0)
  • 2020-12-18 12:22

    It is best to dispatch the work but if you must, maybe something like this. Just call this method to wait for the signal rather than calling the waitone.

    private static TimeSpan InfiniteTimeout = TimeSpan.FromMilliseconds(-1); 
    private const Int32 MAX_WAIT = 100; 
    
    public static bool Wait(WaitHandle handle, TimeSpan timeout) 
    { 
        Int32 expireTicks; 
        bool signaled; 
        Int32 waitTime; 
        bool exitLoop; 
    
        // guard the inputs 
        if (handle == null) { 
            throw new ArgumentNullException("handle"); 
        } 
        else if ((handle.SafeWaitHandle.IsClosed)) { 
            throw new ArgumentException("closed wait handle", "handle"); 
        } 
        else if ((handle.SafeWaitHandle.IsInvalid)) { 
            throw new ArgumentException("invalid wait handle", "handle"); 
        } 
        else if ((timeout < InfiniteTimeout)) { 
            throw new ArgumentException("invalid timeout <-1", "timeout"); 
        } 
    
        // wait for the signal 
        expireTicks = (int)Environment.TickCount + timeout.TotalMilliseconds; 
        do { 
            if (timeout.Equals(InfiniteTimeout)) { 
                waitTime = MAX_WAIT; 
            } 
            else { 
                waitTime = (expireTicks - Environment.TickCount); 
                if (waitTime <= 0) { 
                    exitLoop = true; 
                    waitTime = 0; 
                } 
                else if (waitTime > MAX_WAIT) { 
                    waitTime = MAX_WAIT; 
                } 
            } 
    
            if ((handle.SafeWaitHandle.IsClosed)) { 
                exitLoop = true; 
            } 
            else if (handle.WaitOne(waitTime, false)) { 
                exitLoop = true; 
                signaled = true; 
            } 
            else { 
                if (Application.MessageLoop) { 
                    Application.DoEvents(); 
                } 
                else { 
                    Thread.Sleep(1); 
                } 
            } 
        } 
        while (!exitLoop); 
    
        return signaled;
    }
    
    0 讨论(0)
  • 2020-12-18 12:25

    structure your app so that the main thread only performs UI updates, and all other work is done on secondary threads via a work queue; then add a waiting-for-godot flag to your main thread and use it to guard the method that adds items to the work queue

    out of curiosity: why do you want to do this?

    0 讨论(0)
提交回复
热议问题