2

別のフォーム Form1 によって開かれる次のフォーム Form3 があり、閉じると Form1 が再び開きます。

問題は、Form3 を閉じると、フォームが閉じられた後も DoSomething が実行され続けることです。

DoSomething をスレッドにして IsBackground = true を設定できることは理解していますが、フォームを閉じたときにすべてのプロセスを停止する別の方法はありますか。

このコードは単なる例です。説明用です。

   public partial class Form3 : Form
    {

    public Form3()
    {
        InitializeComponent();
    }
    private void DoSomething()
    {
        int i = 0;
        while(true)
        {
            if (!this.IsDisposed)
            {
                Application.DoEvents();
                i++;
                Thread.Sleep(10);
                label1.Text = i.ToString();
                dataGridView1.Rows.Add();
            }
        }
    }

    private void button1_Click(object sender, EventArgs e)
    {
        DoSomething();
    }

    private void Form3_FormClosed(object sender, FormClosedEventArgs e)
    {
        this.Dispose();
        Form1.Default.Show();
    }

}
4

5 に答える 5

2

あなたは決して抜け出すことはありません(真)。IsDisposed が true のときにループを中断するか、while ループを while(!IsDisposed) に変更するか、ループをいつ中断するかを決定するクラス レベル変数を使用して保存する必要があります。

もう少し制御できるので、私はおそらく後者を選ぶでしょう。

public partial class Form3 : Form
{
    volatile bool clDoSomething;

    public Form3()
    {
        InitializeComponent();
    }
    private void DoSomething()
    {
        int i = 0;
        clDoSomething = true;
        while(clDoSomething)
        {
            Application.DoEvents();
            ++i;
            Thread.Sleep(10);
            label1.Text = i.ToString();
            dataGridView1.Rows.Add();
        }
    }

    private void button1_Click(object sender, EventArgs e)
    {
        DoSomething();
    }

    private void Form3_FormClosed(object sender, FormClosedEventArgs e)
    {
        clDoSomething = false;
        Form1.Default.Show();
    }

}
于 2012-10-03T15:57:04.147 に答える
2

あなたの基本的なアプローチには欠陥があります。

最初に、Application.DoEventsは、本当に必要であり、正しく使用していることが確実でない限り、避けるべきです。ここでは必要なく、正しく使用していません。

ここで本当に必要なのはTimer.

private Timer timer = new Timer();
private int count = 0;
public Form3()
{
    InitializeComponent();

    timer.Tick += timer_Tick;
    timer.Interval = 10;

    //when the form is closed stop the timer.
    FormClosed += (_, args) => timer.Stop();
}

private void button1_Click(object sender, EventArgs e)
{
    count = 0;
    timer.Start();
}

private void timer_Tick(object sender, EventArgs e)
{
    count++;
    label1.Text = count.ToString();
    dataGridView1.Rows.Add();
}

Form作成されると、Timerが設定されます。間隔とともに、ティック イベントが設定されます。DoSomethingtick イベントはメソッドに似ています。UI の応答性を維持しながら、UI スレッドから 10 秒ごとにいくつかのコードを実行する必要があります。フォームが閉じられたら、タイマーを停止するだけで、これらのイベントの発生が停止します。

また、この例では、ボタンを複数回押すとタイマーとカウントがリセットされるだけで、それぞれが 10 ミリ秒ごとに起動する 2 つのループが作成されるわけではないことに注意してください。

于 2012-10-03T16:28:30.307 に答える
0

this.Dispose()必要に応じてorをオーバーライドし、this.Close()手動で DoSomething() を強制終了します。

于 2012-10-03T15:54:36.657 に答える
0

cdhowie の提案と他のすべての入力に感謝します。DoEvents を最後まで刈り取り、IsDipsosed を追加することで問題が解決しました。

public partial class Form3 : Form
{
    public Form3()
    {
        InitializeComponent();
    }
    private void DoSomething()
    {
        int i = 0;
        while ((true) && !this.IsDisposed)
        {
                i++;
                Thread.Sleep(10);
                label1.Text = i.ToString();
                dataGridView1.Rows.Add();
                Application.DoEvents();
        }
    }

    private void button1_Click(object sender, EventArgs e)
    {
        DoSomething();
    }

    private void Form3_FormClosed(object sender, FormClosedEventArgs e)
    {
        Form1.Default.Show();
    }

}
于 2012-10-04T19:45:45.940 に答える