Allister
Allister

Reputation: 851

C# Button - Multiple method calls

A basic C# Problem.

I have two disabled textboxes on my form, and one button. The button is currently like so:

    private void start_Click(object sender, EventArgs e)
    {
        this.two();
        this.hold();
        this.one()
    }

As you can see it calls three other methods that are like so:

The problem I am encountering is that program seems to skip the first call to two. And just hold the program for a second and change one textbox to black.

Thanks for any help!

Upvotes: 2

Views: 3483

Answers (5)

KeithS
KeithS

Reputation: 71573

What you are probably experiencing is that you are running this code on the application's main thread, which is also responsible for responding to Windows GUI messages (like the command to repaint itself after you have changed the textboxes' colors). The program currently does not process this message until after this event handler has completely executed, at which time only one textbox is black.

Application.DoEvents(), as mentioned, will solve the problem by interrupting this handler and allowing the program to process the queued messages from the GUI before proceeding. Another way to do this would be to run this code in a BackgroundWorker, which would use a separate processing thread to tell the GUI thread to recolor the textboxes, while not blocking the GUI thread with the Sleep() command. Generally, using a multithreaded approach is better, as Application.DoEvents() can cause unexpected consequences by forcing the invocation of other event handlers while the current one hasn't finished (for instance, a call to another event handler that throws an exception will throw out through the Application.DoEvents call of the one you've interrupted, which didn't actually have a problem).

Upvotes: 3

ken2k
ken2k

Reputation: 48985

As other mentioned, it's because your UI thread began to sleep before having started to refresh the display.

Never call Thread.Sleep on the UI thread. It'll "block" your program and angers your users. If you have some job to do which requires Thread.Sleep, create a new thread but don't do it in the UI thread.

Upvotes: 3

Douglas
Douglas

Reputation: 54887

Since you’re executing your Thread.Sleep on the UI thread, your form does not get a chance to update itself and repaint with the new colors.

You can introduce an Application.DoEvents call before your hold; however, as others have pointed out, this would result in your UI thread remaining frozen (and unresponsive to user activity) for the one-second delay.

The best way to introduce a delay in your logic is to use a Timer. Here is some sample code which executes two after a one-second delay.

Timer timer = new Timer { Interval = 1000 };
timer.Tick += (sender, e) =>
{
    this.Invoke(new Action(two));
    timer.Stop();
    timer.Dispose();
};
timer.Start();

Upvotes: 1

Fosco
Fosco

Reputation: 38526

Try this:

private void start_Click(object sender, EventArgs e)
{
    this.two();
    Application.DoEvents();
    this.hold();
    this.one();
}

Calling DoEvents(); allows the window to repaint in the middle of the click handler, rather than waiting until completion.

Edit: Please read the comments on this answer... You'll see that it's "bad practice" to perform blocking operations like this.

Upvotes: 2

Thomas Levesque
Thomas Levesque

Reputation: 292465

It doesn't skip the call to two, but since you're blocking the UI thread with your call to Thread.Sleep, the UI never has a chance to refresh to show the effects of two.

You could do something like this:

private void start_Click(object sender, EventArgs e)
{
    this.two()
    Task.Factory.StartNew(() => this.hold())
                .ContinueWith(_ => this.one(), TaskScheduler.FromCurrentSynchronizationContext());
}

It will execute hold in a new thread (thus not freezing the UI) then, when hold is complete, it will execute two on the UI thread.

Upvotes: 2

Related Questions