4

C#2008

以下のコードを使用してソフトフォンにログインしています。ただし、初期化してチェックする必要のあるものがたくさんあるため、ログインプロセスは長いプロセスです。コードを投稿するのに時間がかかるため、ここではほんの少しだけ説明します。

以下のコードでは、各チェックを実行する前に、キャンセルボタンのクリックイベントでCancellationPendingが呼び出されたかどうかをチェックしています。これは正しいです?また、チェックが失敗した場合は、CancelAsyncを呼び出し、e.Cancelをtrueに設定します。

ここで使用した方法が最適な方法かどうかを知りたいのですが。

アドバイスをありがとう、

private void bgwProcessLogin_DoWork(object sender, DoWorkEventArgs e)
    {   
        /*
         * Perform at test to see if the background worker has been
         * cancelled by the user before attemping to continue to login.
         * 
         * Cancel background worker on any failed attemp to login
         */

        // Start with cancel being false as to reset this if cancel has been set to true
        // in the cancel button.
        e.Cancel = false;

        NetworkingTest connection_test = new NetworkingTest();
        if (!this.bgwProcessLogin.CancellationPending)
        { 
            // Check local LAN or Wireless connection               
            if (!connection_test.IsNetworkConnected())
            {
                // Update label
                if (this.lblRegistering.InvokeRequired)
                {
                    this.lblRegistering.Invoke(new UpdateRegisterLabelDelegate(UpdateRegisterLabel), "No network connection");
                }
                else
                {
                    this.lblRegistering.Text = "No network connection";
                }
                // Failed attemp
                this.bgwProcessLogin.CancelAsync();
                e.Cancel = true;
                return;
            }
            // Report current progress
            this.bgwProcessLogin.ReportProgress(0, "Network connected");
        }
        else
        {
            // User cancelled 
            e.Cancel = true;
            return;
        }

        // Test if access to Server is available
        if (!this.bgwProcessLogin.CancellationPending)
        {
            if (!connection_test.IsSIPServerAvailable())
            {
                // Update label
                if (this.lblRegistering.InvokeRequired)
                {
                    this.lblRegistering.Invoke(new UpdateRegisterLabelDelegate(UpdateRegisterLabel), "Server unavailable");
                }
                else
                {
                    this.lblRegistering.Text = "Server unavailable";
                }
                // Failed attemp
                this.bgwProcessLogin.CancelAsync();
                e.Cancel = true;
                return;
            }
            // Report current progress
            this.bgwProcessLogin.ReportProgress(1, "Server available");
        }
        else
        {
            // User cancelled 
            e.Cancel = true;
            return;
        }
        .
        .
        .
}


 private void bgwProcessLogin_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {   
        // Check for any errors
        if (e.Error == null)
        {
            if (e.Cancelled)
            {
                // User cancelled login or login failed                
            }
            else
            {
                // Login completed successfully                
            }
        }
        else
        {
            // Something failed display error
            this.statusDisplay1.CallStatus = e.Error.Message;
        }
    }


 private void bgwProcessLogin_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        this.lblRegistering.Text = e.UserState.ToString();
    }

private void btnCancel_Click(object sender, EventArgs e)
    {
        // Cancel the logging in process
        this.bgwProcessLogin.CancelAsync();
        this.lblRegistering.Text = "Logged out";
}
4

4 に答える 4

8

おそらく 1 つだけ問題があります。DoWork イベント ハンドラーの操作の 1 つが長時間続く場合です。この場合、保留中の操作を中止できるのは、その操作が完了した後でのみです。DoWork イベントのすべての操作が非常に長く続くことができない場合 (たとえば、5 秒以内)、すべて問題ありませんが、操作の 1 つが長時間 (たとえば、5 分間) 続く場合、この場合、ユーザーはこの操作が完了するまで待ちます。

DoWork に長期的な操作が含まれている場合は、AbortableBackgroundWorker などを使用できます。このようなもの:

public class AbortableBackgroundWorker : BackgroundWorker
{
    private Thread workerThread;

    protected override void OnDoWork(DoWorkEventArgs e)
    {
        workerThread = Thread.CurrentThread;
        try
        {
            base.OnDoWork(e);
        }
        catch (ThreadAbortException)
        {
            e.Cancel = true; //We must set Cancel property to true!
            Thread.ResetAbort(); //Prevents ThreadAbortException propagation
        }
    }


    public void Abort()
    {
        if (workerThread != null)
        {
            workerThread.Abort();
            workerThread = null;
        }
    }
}

この場合、保留中の操作を完全に中止できますが、いくつかの制限もあります (マネージド スレッドの中止といくつかの制限の詳細については、 Rotor を使用した ThreadAbortException の深さの配管を参照してください)。

PS InvokeRequired をより使いやすい形式でラップする必要があるという Oliver の意見に同意します。

于 2010-01-29T08:13:53.590 に答える
1

あなたはそれを正しい方法でやっていると私は信じています。スレッドを終了または中止できるスレッド メンバーが見つかりますが、このような目的でそれらを使用したくはありません。すべての「キャンセルされた」チェックをコードに含めるのは少し奇妙に見えるかもしれませんが、これにより、スレッドを終了するタイミングを正確に制御できます。ワーカー スレッドを「乱暴に」中止した場合、スレッドはいつ終了するかを制御できず、状態が破損する可能性があります。

于 2009-05-05T19:29:33.590 に答える
1

DoWork() 関数内で、 を書き...ました。表示されている 2 つのタスクのように、同じ構造のタスクがいくつ来るかによって、この構造を独自のメソッドにリファクタリングし、変更部分をパラメーターとして与えることができます。

また、この InvokeRequired if-else ブランチは、出力文字列を 2 倍にしています。ここでstackoverflowまたはWebを少し検索すると、この倍増を達成するためのパターンが表示されるはずです。

他のすべては非常によく見えます。

于 2010-01-29T07:57:28.303 に答える
0

this.bgwProcessLogin.CancelAsync(); を呼び出す必要のないことが 1 つあります。この e.Cancel = true; を設定するだけです。

于 2009-05-06T15:13:32.403 に答える