2

私はC#、RestSharp、およびスレッド化に慣れていないので、私がやろうとしていることは次のとおりです.tumblrに
写真をアップロードできるようにするプログラムを作成し、これまでのところアップロードが機能しています. ExecuteAsync()ここで、停止ボタンが機能する必要があります。これは、の代わりに使用する必要があることを意味すると思いますExecute()。次のように、コードをバックグラウンドワーカーに入れています。

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    if (backgroundWorker1.CancellationPending)
    {
        e.Cancel = true;
        MessageBox.Show("You pressed Cancel.");
    }
    else
    {
    var restClient = new RestClient("http://tumblr.com/api/write");
    foreach (string item in queueBox.Items)
    {
        var request = new RestRequest(Method.POST);
        request.RequestFormat = DataFormat.Json; //I don't know if this line is necessary
        request.AddParameter("email", usernameBox.Text);
        request.AddParameter("password", passwordBox.Text);
        request.AddParameter("type", "photo");
        request.AddFile("data", FolderName + "\\" + item);
        RestResponse response = restClient.Execute(request);
        doneBox.Invoke(new UpdateTextCallback(this.UpdateText),
            new object[] { item });
    }
    }
}

私はこれを正しく設定したと信じています。押すとそれに応じuploadて進みます。ただし、これはブロック elseしていると思います。これにより、コードがフラグのチェックを続行できなくなります。 これが私がそれをキャンセルしようとする方法です。RestResponse response = restClient.Execute(request);

public void stopButton_Click(object sender, EventArgs e)
{
    doneBox.Items.Add("You pressed the stop button.");
    backgroundWorker1.WorkerSupportsCancellation = true;
    backgroundWorker1.CancelAsync();
}

また、これが関連する場合、私は持っています:

public delegate void UpdateTextCallback(string item);これにより、上で見たようにUpdateTextとを呼び出すことができます。FinishedTextbackgroundWorker1_DoWork



ExecuteAsync私の質問では、このコンテキストでどのように使用できますか? 検索しましたが、役立つものが見つかりません。自分のコードに似た例が見つかりません。また、c# を初めて使用するため、必要なものに変換できません。

また、提案をお待ちしております。私のコードに非効率性が見られたり、そうでない場合は、喜んで提案を受け入れます。

ありがとうございました。

4

1 に答える 1

3

ここには、潜在的な問題がいくつかあります。

まず、バックグラウンド スレッドから UI 要素にアクセスしようとしているようです (メッセージ ボックスも開きます)。これにより、CrossThread 例外がスローされる可能性があります*。

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

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    var restClient = new RestClient("http://tumblr.com/api/write");
    foreach (string item in queueBox.Items)
    { 
        //This should be inside the foreach 
        //as it is your loop that will check for cancel. 
        //Your code is procedural once it is in the backgroundworker
        //so it would never return to the spot you had it
        if (backgroundWorker1.CancellationPending)
        {
            e.Cancel = true;
            //MessageBox.Show("You pressed Cancel.");
            //Removed this to the background worker completed method below
            //This avoids any UI cross thread exceptions
            return;
        }
        var request = new RestRequest(Method.POST);
        //I believe Json is default for Restsharp, but you would have to play with it
        request.RequestFormat = DataFormat.Json; //I don't know if this line is necessary
        request.AddParameter("email", usernameBox.Text);
        request.AddParameter("password", passwordBox.Text);
        request.AddParameter("type", "photo");
        request.AddFile("data", FolderName + "\\" + item);
        //If you just pass in item to the below Func, it will be a closure
        //Meaning, any updates in the loop will propogate into the Action
        var newItemToAvoidClosure = item;
        //To use Async, you set up the callback method via a delegate
        //An anonymous method is as good as any here
        restClient.ExecuteAsync(request, 
            response=>
            { 
                //Maybe you should do something with the response?
                //Check the status code maybe?
                doneBox.Invoke(new UpdateTextCallback(this.UpdateText),
                    new object[] { newItemToAvoidClosure });
            }
        );
    }
}

バックグラウンド ワーカーのRunWorkerCompletedメソッドをこれに接続し、ここですべての後処理を実行します。

private void backgroundWorker1_RunWorkerCompleted(object sender,
    RunWorkerCompletedEventArgs e)
{
    if(e.Cancelled)
        MessageBox.Show("You pressed Cancel"
}

また、4.0 以降を使用している場合は、Task Parallel Libraryを調べることをお勧めします。それはあなたのコードをよりきれいにすることができます IMO :)。

最後に、上記のコードに関する注意点として、すべての Rest 呼び出しが完了する前に、バックグラウンド ワーカーが完了して戻る可能性が高いということです。これはおそらくかなり速く実行され、この方法ではキャンセルできないため、呼び出しは続行されたままになります (バックグラウンドワーカーは既に完了しています) (ただし、Rest 呼び出しごとにこれを行う方法があると思います)。したがって、実際の問題は、キャンセル チェックがコードの間違った部分にあったことのように思えます (各ファイルが処理された後にチェックできるように、ループ内に移動したことに注意してください)。あなたはすでにバックグラウンドスレッドで実行しているので、別の非同期を呼び出す意味がないように思えます(送信されるデータのループをオフロードし、実際の送信をオフロードすることが目的でない限り)。

では、結論として。非同期を呼び出す方法を提供しましたが、より大きな問題は、キャンセル呼び出しを適切にチェックしていなかったことだと思います。

*UI要素にアクセスして更新していないだけなので、そうではないかもしれません.

于 2012-03-23T04:00:12.897 に答える