2
   private void AddMyScrollEventHandlers()
   {
       VScrollBar vScrollBar1 = new VScrollBar();
   }

   private void button1_Click(object sender, EventArgs e)
   {
       while (true)
       {
           if (vScrollBar1.Value + 1 < vScrollBar1.Maximum)
           {
               vScrollBar1.Value = vScrollBar1.Value + 1;    
               label1.Text = vScrollBar1.Value.ToString();                       
           }       
           else 
           {         
               break;      
           }

           System.Threading.Thread.Sleep(200);
       }
   }

   private void button2_Click(object sender, EventArgs e)
   {
       // vScrollBar1.Scroll
   }

私はC#を初めて使用します。私はスクロールに取り組んでいました。ここで私が欲しかったのは、誰かがbutton1をクリックすると、スクロールが自動的に最後に移動し、label1に段階的な値を表示したかったということです。また、誰かがbutton2をクリックすると、スクロールが停止します。

ここで問題となるのは、label1の値が徐々に変化しないことです。スクロールが停止すると値が1回表示されます。

また、スクロールを続行するとき、つまりループが機能しているときは、button2をクリックできません。実はフォームもクリックできません。

誰かが私にこれを行う方法についていくつかのアイデアを教えてください。

4

3 に答える 3

5

これは、タスクを実行しているスレッドがビジーであり、UIを更新するのと同じスレッドであるために発生します。マルチスレッドソリューションを使用できます。を見てみましょう BackgroundWorker

于 2013-03-14T20:23:43.970 に答える
1

すべてのUIイベントはアプリケーションのメインスレッドで実行されるため、アプリケーションは一度に1つのイベントしか処理できません。アプリケーションがイベントを処理しているとき、他のイベントは処理されません。

UI関連の作業を定期的に行っているため、最適なオプションは次のTimerクラスを使用することです。

  1. Timerツールボックスからフォームにドロップします。
  2. プロパティウィンドウで、間隔を200に設定します。
  3. タイマーオブジェクトをダブルクリックして、Tickイベントハンドラーを作成します。
  4. このコードを新しく作成したtimer1_Tickメソッドに入れます。

     if (vScrollBar1.Value + 1 < vScrollBar1.Maximum)
     {
         vScrollBar1.Value = vScrollBar1.Value + 1;    
         label1.Text = vScrollBar1.Value.ToString();                       
     }       
     else 
     {         
         timer1.Stop();
     }
    
  5. 以下のようにメソッドを変更します。

    private void AddMyScrollEventHandlers()
    {
        timer1.Start();
    }
    
    private void button2_Click(object sender, EventArgs e)
    {
        timer1.Stop();
    }
    

これで完了です。

于 2013-03-14T20:26:50.023 に答える
0

Agustin MerilesBackgroundWorkerが提案しているように、コントロールを使用することをお勧めします。ただし、注意すべきもう 1 つの重要な点は、メソッドを使用して別のスレッドからコントロールを更新する必要があるということです。Control.Invoke(...)

あなたのコードを修正し、サンプル アプリケーションでテストしましたが、正しく動作しているようです。

BackgroundWorkerまず、フォームに新しいコントロールを追加し、backgroundWorker1_DoWorkそのDoWorkイベントに割り当てます。

次に、以下のコードを使用できます。

private void button1_Click(object sender, EventArgs e)
{
    //code from here is moved to BackgroundWorker control
    backgroundWorker1.RunWorkerAsync();
}

private void button2_Click(object sender, EventArgs e)
{

}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    //while (true)
    //the condition directly in the while looks more clear to me
    while (vScrollBar1.Value + 1 < vScrollBar1.Maximum)
    {
        //update controls using Invoke method and anonymous functions
        vScrollBar1.Invoke((MethodInvoker)delegate() { vScrollBar1.Value += 1; });

        label1.Invoke((MethodInvoker)delegate() { label1.Text = vScrollBar1.Value.ToString(); });

        //when called inside BackgroundWorker, this sleeps the background thread, 
        //so UI should be responsive now
        System.Threading.Thread.Sleep(200);
    }
}

このコードを使用する際に問題がある場合は、お知らせください。

アップデート

コメントで述べたように、のProgressChangedイベントを使用することもできますBackgroundWorker。コードにさらに変更を加える必要がありますが、この場合により適しています。これに関する情報は、http: //msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.progresschanged.aspxで確認できます。

ループ内でより多くの処理を行う他のコードを追加しない場合は、 MD.Unicornの回答で提案されているように、コントロールをwhile使用することもできます。Timer

于 2013-03-14T20:41:40.040 に答える