0

次のコードを使用して、データベース内のすべての学生にSMSを送信します。

private void btnsend_Click(object sender, EventArgs e)
    {
        foreach (Control c in Controls)
        {
            c.Enabled = false;
        }
        if (!bgw.IsBusy)
        {
            bgw.RunWorkerAsync();
        }
    }
    private void bgw_DoWork(object sender, DoWorkEventArgs e)
    {
        for (int i = 0; i < dt.Rows.Count; i++)
        {
            Invoke((MethodInvoker)delegate()
            {
                using (var sp = new SerialPort(cbcomport.Text))
                {
                    sp.Open();
                    sp.WriteLine("AT" + Environment.NewLine);
                    sp.WriteLine("AT+CMGF=1" + Environment.NewLine);
                    sp.WriteLine("AT+CMGS=\"" + dt.Rows[i]["PhoneNo"] + "\"" + Environment.NewLine);
                    sp.WriteLine(tbsms.Text + (char)26);
                    if (sp.BytesToRead > 0)
                    {
                        tbsentto.Text = i + 1 + " of " + dt.Rows.Count;
                    }
                }
            });
            Thread.Sleep(5000);
        }
    }
    private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        foreach (Control c in Controls)
        {
            c.Enabled = true;
        }
    }

私の質問は次のとおりです。例外が発生した場合、SMSが学生に送信されている間。たとえば、ポート「COM5」は存在しません。再試行とキャンセルのボタンを使用して、同じシステムメッセージをユーザーに表示したい。問題を解決した場合。つまり、デバイスを接続したユーザーが再試行ボタンを押して同じポイントからスレッドを再開し、ユーザーがキャンセルボタンを押した場合に一時停止したスレッドを停止したい。

4

3 に答える 3

1

このようなスキームの場合、一般的な考え方は次のことです。

  • ワーカーからスローされる可能性のある例外をキャッチします(ただし、処理できることがわかっている例外のみ。すべての例外をキャッチするのはです!)
  • UIスレッドに通知してユーザーにプロンプ​​トを表示する
  • UIスレッドが入力を受け取るまで実行を一時停止します
  • 入力がそのように示している場合は実行を中止します

最後の2つの項目には、タスクを中止する必要があるかどうかを示す、AutoResetEventおよび状態変数(少なくともaでも可能)などの待機可能なオブジェクトを使用します。boolこれらの変数は、UIスレッドとワーカーの両方からアクセスできる必要があります。

AutoResetEvent pauseEvent(false);
bool shouldAbort;

ワーカーのコードは次のようになります。

for (int i = 0; i < dt.Rows.Count; i++)
{
    try
    {
        // your existing code goes here
    }
    catch (SomeException ex) // do not catch all exceptions!
    {
        BeginInvoke(...);     // tell the UI thread something bad happened
        pauseEvent.WaitOne(); // and block the worker until user gives input
        if (shouldAbort)
        {
            // cleanup any other resources if required and then
            break;
        }
    }
}

このBeginInvoke行では、ユーザーに適切なメッセージを表示して指示を要求するメソッドを呼び出す必要があります。はすぐに戻り、ワーカーはを呼び出すことでをBeginInvoke無期限にブロックします。AutoResetEventpauseEvent.WaitOne

UIメソッドはユーザーにクエリを実行し、応答を受信した後、次のように通知する必要がありますpauseEvent

pauseEvent.Set();

これにより、ワーカーのブロックが解除され、実行を再開できるようになります。コードの構造により、これはループの次の反復を続行することを意味します。代わりにワーカーを中止する場合は、シグナリングのshouldAbortにに設定します。true pauseEvent

ブロックi内でデクリメントした場合、(スキップして次の例外を続行する代わりに)例外をスローした反復をコードに再試行させることもできます。catch

于 2012-04-07T08:53:46.947 に答える
1

これを試して

private void btnsend_Click(object sender, EventArgs e)
    {
        foreach (Control c in Controls)
        {
            c.Enabled = false;
        }
        if (!bgw.IsBusy)
        {
            bgw.RunWorkerAsync();
        }
    }
    private void bgw_DoWork(object sender, DoWorkEventArgs e)
    {
        for (int i = 0; i < dt.Rows.Count; i++)
        {
            if ((bgw.CancellationPending == true))
            {

                e.Cancel = true;
                break;
            }
            else
            {
                Invoke((MethodInvoker)delegate()
                {
                    using (var sp = new SerialPort(cbcomport.Text))
                    {
                        try
                        {
                            sp.Open();
                            sp.WriteLine("AT" + Environment.NewLine);
                            sp.WriteLine("AT+CMGF=1" + Environment.NewLine);
                            sp.WriteLine("AT+CMGS=\"" + dt.Rows[i]["PhoneNo"] + "\"" + Environment.NewLine);
                            sp.WriteLine(tbsms.Text + (char)26);
                            if (sp.BytesToRead > 0)
                            {
                                tbsentto.Text = i + 1 + " of " + dt.Rows.Count;
                            }
                            Thread.Sleep(5000);
                        }
                        catch (Exception ex)
                        {
                            if (MessageBox.Show(ex.Message, "Error", MessageBoxButtons.RetryCancel, MessageBoxIcon.Error) == System.Windows.Forms.DialogResult.Retry)
                            {
                                try
                                {
                                    sp.Open();
                                    sp.WriteLine("AT" + Environment.NewLine);
                                    sp.WriteLine("AT+CMGF=1" + Environment.NewLine);
                                    sp.WriteLine("AT+CMGS=\"" + dt.Rows[i]["PhoneNo"] + "\"" + Environment.NewLine);
                                    sp.WriteLine(tbsms.Text + (char)26);
                                    if (sp.BytesToRead > 0)
                                    {
                                        tbsentto.Text = i + 1 + " of " + dt.Rows.Count;
                                    }
                                    Thread.Sleep(5000);
                                }
                                catch (Exception ex2)
                                {
                                    MessageBox.Show(ex2.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                    bgw.CancelAsync();

                                }
                            }
                            else
                            {
                                bgw.CancelAsync();
                            }
                        }
                    }
                });
            }
        }
    }
    private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        foreach (Control c in Controls)
        {
            c.Enabled = true;
        }
    }
于 2012-04-10T09:31:22.980 に答える
0

syncスレッド間でオブジェクトを使用する必要があります。特にセクションでここを見 てくださいwait handlers

于 2012-04-07T08:08:23.470 に答える