문제

maybe it is a bad question, but I have a Client App which sends some Commands to the server. I made a little function for sending commands, which simply waits until a message is received over AutoResetEvent.WaitOne() and then returns the message as string. I used this function very often in my client app, because it was a fast way to implement sth.

Now I want to show a LoadingCircle in this app while it is waiting from the response from the Server. I already wrote sth for that in the message receiving function, which simply adds the control to the Form. This is working find, but UserControl(Loading Circle), which redraws after some milliseconds, doesnt redraw anymore, because AutoResetEvent.WaitOne() is blocking the GUI Thread. I know that I could move the message receiving part into another Thread, but I dont want to change the concept of this function, because I used the message receiving function over 150x.

So my question is: Is there a lazy way to do that, so that It does GUI Events while its waiting, or maybe I can move the drawing part of the LoadingCircle Control into another Thread?

Any help will be greatly appreciated

도움이 되었습니까?

해결책 2

I found a small fix for that here, which works well(I cant take credit for it)

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;
}

다른 팁

You have essentially taken an async operation and turned it into a synchronous operation via AutoResetEvent.WaitOne. And now you want to turn it back into an async operation.

My suggestion would be to separate the function from the UI. Then tool a synchronous and an async option. That way you get to keep a fully functioning app and can incrementally release during your code re-write of the 150 instances that need changed.

The new async and await keywords in 4.5 should serve you well here.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top