Click here to Skip to main content
15,880,891 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
Hello,

I have a backgrounworker thread that calls a method (Connect()). When that process is completed it comes to RunCompleted where I check it its connectedToServer or not. I not, I call a method (CallToReconnect()). Over here, I got to wait for 20 secs updating the status bar on each sec and finally call a method that starts the background thread. For this :

C#
private void CallToReConnect()
{
    Logger.LogInfo("Call To ReConnect");
    currentState = RECONNECTING;
    int counter = 20;
    cancelSplitButton.Visible = true;
    // Try again after 20 secs
    System.Windows.Threading.DispatcherTimer timer = new  System.Windows.Threading.DispatcherTimer();
    timer.Tick += delegate
    {
        statusLabel1.Text = "ReConnect in " + counter.ToString() + " secs";
        counter--;
       // Thread.Sleep(1000);
        if (counter == 0)
            timer.Stop();
    };
    timer.Interval = new TimeSpan(0, 0, 1);
    timer.Start();
    //Thread.Sleep(20000);

    ConnectClicked();
}


This code starts the DispatchTimer and then also starts ConnectClicked(). I want to finish that part before Connectclicked() is called, so my status bar can see "Reconnecting in XX secs" - XX - 20, 19, 18, etc. If I replace that with Thread.Sleep(20000) then it waits for 20 secs & then only it starts. But I want to show the Reconnecting in status bar so I opted this way.

Where am I going wrong ? How to accomplish the goal ?

Thanks
Posted

Move the call to ConnectClicked into the timer event handler:

private void CallToReConnect()
{
    Logger.LogInfo("Call To ReConnect");
    currentState = RECONNECTING;
    int counter = 20;
    cancelSplitButton.Visible = true;
    // Try again after 20 secs
    System.Windows.Threading.DispatcherTimer timer = new  System.Windows.Threading.DispatcherTimer();
    timer.Tick += delegate
    {
        statusLabel1.Text = "ReConnect in " + counter.ToString() + " secs";
        counter--;

        if (counter == 0) {
            timer.Stop();
            ConnectClicked(); // might need to Invoke it?
        }
    };
    timer.Interval = new TimeSpan(0, 0, 1);
    timer.Start();
}

I'm not sure which thread timer events are dispatched in, you may have to use Invoke if you want ConnectClicked to be run in the UI thread.
 
Share this answer
 
Comments
All Time Programming 17-Jun-11 12:04pm    
Thanks BobJanova, that did the work for me. Their was no need to use Invoke to call ConnectClicked. CallToReConnect is called on normal UI thread only.
Using thread and timer at the same time makes no sense. Use Thread.Sleep. This is all you need.

Also, avoid using timer by all means. In explained it in my past answer:
Timer Threading in C#[^].

—SA
 
Share this answer
 
Comments
BobJanova 17-Jun-11 11:10am    
Using a timer for this kind of UI interaction where it doesn't matter if it is really 20.01s is fine, no?
Sergey Alexandrovich Kryukov 18-Jun-11 2:09am    
There are other reasons not to use times, not just seconds. Why using a timer where a thread could perfectly work? OP's code suffers "accidental complexity".
--SA
SA, then by using Thread.Sleep, how do I update the text in statusbar as wanted ? I am not able to handle that part as expected hence tried with timer.

Do you have any idea to avoid timer, use Thread.Sleep & update the text every sec ?
 
Share this answer
 
SAKryukov for sure meant to make the thread sleep for one second at a time and use a counter to remember how many 1-second-sleep-cycles have passed.

You could try something like this:
private void CallToReConnect()
{
    for(int counter = 20; counter >= 0; counter--)
    {
        System.Threading.Thread.Sleep(1000);

        ShowProgress(counter);
    }
}

private delegate void ShowProgressDelegate(int progress);
private void ShowProgress(int secondsToWait)
{
    // Don't use a non-existent control
    if(statusLabel1 == null)
        return;
    
    // If not already in GUI thread, ask GUI thread to update label
    if(statusLabel1.InvokeRequired)
    {
        statusLabel1.Invoke(
            new ShowProgressDelegate(ShowProgress),
            new object[]{secondsToWait}
        );
        return;
    }

    // Actually update label text
    statusLabel1.Text= "ReConnect in " + secondsToWait.ToString() + " secs";
}
This should make the invoking work.

As for causing the application to crash by shutting it down, that's what you wanted. The application is shut down.

No. I'm just kidding.
You could set your BackgroundWorker to SupportsCancellation = true and call CancelAsync() on it when shutting the application down.
This way, you could notice the CancellationPending property to become true. Check it from within the loop and stop CallToReconnect when appropriate.

Surely someone knows of a nicer way of invoking with less code and without the need for a seperate method and delegate?
 
Share this answer
 
v2
Comments
All Time Programming 17-Jun-11 5:37am    
Thank lukeer, Sorry am not good at this. The above code gave error "The name 'SomehowInvoke' does not exist in the current context". I added a method SomehowInvoke but that also didn't work - knowing that, that is not correct. What do I nned to correct with above code to make it work ?
lukeer 17-Jun-11 8:39am    
I updated my answer to cover the invoking.
All Time Programming 17-Jun-11 6:31am    
What is the safe way wo work with this. If the user clicks close btn at that time then also the app doesn't crash. @Lukeer, with the above version if user tries to close app "x" it crashes.
lukeer 17-Jun-11 8:40am    
See my updated answer. Maybe that covers the problem?
C#
private void CallToReConnect()
        {
            for (int i = 0; i < 21; i++)
            {
                statusLabel1.Text = "ReConnect in " + i.ToString() + " seconds";
                System.Threading.Thread.Sleep(1000);
                Application.DoEvents();
            }
            ConnectClicked();
        }



When you use Thread.Sleep, always remember to call Application.DoEvents()
 
Share this answer
 
v2
Comments
BobJanova 17-Jun-11 11:02am    
Nonono ... this is a bad hack that will result in semi-responsive UI. You should never sleep the main UI thread.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900