0

タイマーを開始し、時間のかかる操作を実行し、その操作が行われている間、一定の間隔で進行状況バーを更新する単純なフォームがあります。現在、時間のかかる操作はSearchButton. ただし、時間のかかる操作 (この場合はダウンロード) には数秒かかりますが、進行状況バーには何も起こりません。

public partial class Form1 : Form
{
    System.Windows.Forms.Timer searchProgressTimer;

    public Form1()
    {
        InitializeComponent();
        this.searchProgressTimer = new System.Windows.Forms.Timer();
    }

    private void InitializeTimer()
    {
        this.searchProgressTimer.Interval = 250;
        this.searchProgressTimer.Tick += new EventHandler(searchProgressTimer_Tick);
    }

    void searchProgressTimer_Tick(object sender, EventArgs e)
    {
        searchProgressBar.Increment(1);
        if (searchProgressBar.Value == searchProgressBar.Maximum)
            this.searchProgressTimer.Stop();
    }

    private void SearchDatabase_Click(object sender, EventArgs e)
    {
        this.searchProgressTimer.Start();

        // Time-consuming operation
        String filename = @"http://www.bankofengland.co.uk/publications/Documents/quarterlybulletin/qb0704.pdf";
        WebClient webClient = new WebClient();
        webClient.DownloadFileAsync(new Uri(filename), @"file.pdf");
        int test;
        for (int i = 0; i < 100000; i++)
            for (int j = 0; j < 100000; j++)
                test = i + j;


        this.searchProgressTimer.Stop();

    }
}

(実際の時間のかかる操作はデータベース検索であるため、関数の名前は少し奇妙ですが、そのコードは正しく機能しますが、非常に長く複雑です)。

このコードをデバッグすると、SearchButton_Clickイベント ハンドラーが正しく起動することがわかりますが、コードがsearchProgressTimer_Tickイベント ハンドラーにジャンプすることはありません。何か案は?

4

4 に答える 4

3

ここで行っていることは少し混乱しています。あなたが実際にどこかでタイマーを初期化していると仮定すると、これが起こっていることだと思います...

クラスは完全にフォームのForms.Timerメッセージループで実行されるため、そのスレッドで関数が実行されている間は起動できません。したがってStart()、タイマーを使用していても、Click()関数はタイマーと同じスレッドで実行されているため、その関数が戻るまでタイマーは起動できません。Stop()ただし、その関数がタイマーを返す前に。

おそらくあなたは見たいと思うでしょうThreading.Timer。ただし、GUIのメッセージループを処理できるように、理想的には、実行している「作業」は、データベースで動作している場合でも、単純にネストされたforループである場合でも、別のスレッドで実行する必要があります。

このために別のスレッドを生成する場合は、UIの変更またはメインUIスレッドのUI要素への変更を呼び出すことを忘れないでください。

于 2012-07-13T18:43:12.197 に答える
2

これは、GUIの更新がデータベース操作と同じスレッドで行われているためです。データベース操作は別のスレッドで実行し、GUIスレッドを呼び出して更新を通知する必要があります。それがかなりよく説明しているので、これを見てください。

http://www.dotnetperls.com/progressbar

于 2012-07-13T18:43:57.313 に答える
2

したがって、1)InitializerTimer()の呼び出しはどこにも表示されません。

2)System.Windows.Forms.Timerは、UIスレッドでティックイベントを発生させます。時間のかかる操作を行っているのとまったく同じスレッドです。偶数を処理するには、メッセージポンプに制御を委ねる必要があります。

于 2012-07-13T18:45:45.930 に答える
1

このコードをデバッグすると、SearchButton_Clickイベントハンドラーが正しく起動することがわかりますが、コードがsearchProgressTimer_Tickイベントハンドラーにジャンプすることはありません。

ルーチンをフォームのコンストラクターに移動してみてください。IntializeTimer()タイマーのティックイベントを接続していないように見えるからです。

public Form1()
{
  InitializeComponent();
  this.searchProgressTimer = new System.Windows.Forms.Timer();
  this.searchProgressTimer.Interval = 250;
  this.searchProgressTimer.Tick += new EventHandler(searchProgressTimer_Tick);
}
于 2012-07-13T18:43:19.110 に答える