3

私はC#が初めてです。私は 2buttonと 2を持っていlabelます。私が欲しいのは、クリックbutton1するとカウントが開始label1され、 に表示されるということです。それを押すbutton2と、カウントダウンが再開され、カウントダウンがbutton1開始さbutton2、label2 に表示されます。これが私のコードです

bool testt = true;
int i = 0;
int j = 0;

private void button1_Click(object sender, EventArgs e)
{
    while (testt)
    {
        label1.Text = i.ToString();
        i++;
        System.Threading.Thread.Sleep(50);
        if (i > 5000)
        {
            i = 0;
        }
    }
}

private void button2_Click(object sender, EventArgs e)
{
    testt = false;
    while (!testt)
    {
        label2.Text = j.ToString();
        j++;
        System.Threading.Thread.Sleep(50);
        if (j > 5000)
        {
            i = 0;
        }
    }
}

ここでの問題は、あるボタンをクリックすると、別のボタンをクリックできないことです。どのボタンが押されたかを検出するために、グローバル変数を使用しました。しかし、うまくいきません。どうすればこれを機能させることができますか?

4

2 に答える 2

2

これはすべて UI スレッドで実行しているため、ブロックしています。Control.Invokeメインスレッドがメッセージポンプを実行する時間を確保できるように、別のスレッドに実際のカウントを実行させ、使用してラベルの変更をメインスレッドに委譲する必要があります。組み込みの を使用するか、またはBackgroundWorkerでスレッドを作成することができます。ThreadPoolTaskFactory

LINQ と ThreadPool を使用してこれを実現する方法の短い例を書きました。これは設計上の最善のアプローチではありませんが、適切なソリューションを開発するための出発点となります。

    semaphore = true;
    int i = 0;
    int j = 0;

    private void button1_Click(object sender, EventArgs e)
    {
        semaphore = true;
        ExecuteAsync(()=>
            {
                while (semaphore)
                {
                    //Dispatch a call to the UI thread to change the label
                    Invoke((MethodInvoker)(() => ChangeLabel(label1, i.ToString())));
                    i++;
                    Thread.Sleep(50);
                    if (i > 5000)
                    {
                        i = 0;
                    }
                }
            });
    }

    //Executes a function on a ThreadPool thread
    private void ExecuteAsync(Action action)
    {
        ThreadPool.QueueUserWorkItem(
            obj => action());
    }

    private void ChangeLabel(Label label, string labelText)
    {
        label.Text = labelText;
    }

    private void button2_Click(object sender, EventArgs e)
    {
        semaphore = false;
        ExecuteAsync(() =>
                {
                    while (!semaphore)
                    {
                        //Dispatch a call to the UI thread to change the label
                        Invoke((MethodInvoker)(() => ChangeLabel(label2, j.ToString())));
                        j++;
                        Thread.Sleep(50);
                        if (j > 5000)
                        {
                            i = 0;
                        }
                    }
                });
    }
于 2013-03-16T22:01:41.990 に答える
0

ここでの問題は、スレッドの問題です。

winforms がある場合、メイン スレッドには、インターフェイスを表示してインタラクティブにし、与えられたタスクを実行する仕事があります。

コードで、カウントダウンを開始します。しかし、そこでは、インターフェイスを機能させる同じスレッドが現在ビジーで値を減らしているため、準備が整うまでインターフェイスを更新したり、ボタンに応答したりしません。

あなたが望むのは、あなたのためにカウントダウンを行うためのヘルパースレッドです(または、正直なところ、代わりにタイマーを開始します)。そうしないと、そのループが終了するまで、インターフェイスは非インタラクティブになります。

タイマーはそれを行う最も簡単な方法です。

http://msdn.microsoft.com/en-us/library/system.windows.forms.timer.aspx

于 2013-03-16T21:57:42.833 に答える