2011-08-16 6 views
1

WP7アプリケーションのニュースを更新するための更新ボタンがあります。私はエラーにC# - 同時I/O操作の例外

"WebClient does not support concurrent I/O operations" . 

を取得しています更新ボタンをダブルまたはトリプルクリックするとそれは要求にトリプル回送信し、それがクラッシュ作っているので、私はthatsのだと思います。ここに私のクリックコードがあります。

private void NewsRefresh_Click(object sender, RoutedEventArgs e) 
    { 
     var vm = this.DataContext as MainPageViewModel; 
     if (vm != null) 
     { 
      vm.UpdateNews(); 
     } 
    } 

「プロセスがビジー状態であれば」とすることができます。

+0

プライベートブールisPendingRefresh – sll

+0

これについての手がかりやガイドは? – FrankCap

答えて

1

「簡単」な方法(ない防弾が):

private void NewsRefresh_Click(object sender, RoutedEventArgs e) 
{ 
    try 
    { 
     NewsRefresh.Enabled = false; 
     var vm = this.DataContext as MainPageViewModel; 
     if (vm != null) 
     { 
      vm.UpdateNews(); 
     } 
    } 
    finally 
    { 
     NewsRefresh.Enabled = true; 
    } 
} 

より困難なアプローチがMainPageViewModelであり、どのようなUpdateNews()は正確に何の詳細を必要とします。基本的には、WebClientインスタンスを格納している場合は常に、状態値を格納する必要があります。 WebClientを使用する前に、すでにWebClientを使用しているかどうかを確認する必要があります。この問題は、複数のスレッドが1つのインスタンス上で動作する場合、または複数の操作(UpdateNews以外)の場合に発生します。複数のスレッドが含まれている場合は、最も簡単な方法はWebクライアントの使用方法を囲むことです。Mutex

もちろん、WebClientインスタンスを再利用しないで、新しい要求ごとに新しいインスタンスを作成することもできます。

UPDATE

まあ、まあ、DownloadStringAsyncを使用すると、確かに物事を楽しくするために起こっています。上記のコード再有効化コードを移動しない限り、UIを無効にすることはできません。最後の提案をして、WebClientの新しいインスタンスを作成するのが最も簡単です。私はWebClient自身が本当に好きではなく、WebRequest.Createを好む。

+0

これを確認します。 Btw、UpdateNews()はnewsWebClient.DownloadStringAsyncフィードをダウンロードしています(新しいUri( "http://feeds.bbci.co.uk/news/rss.xml"))。 – FrankCap

2

WebClientはあまり柔軟ではありませんが、本当に使用したい場合は、IsBusyプロパティを使用して、実行中の操作をキャンセルできます。その後、キャンセルされると再起動できます。同期には重要な問題があります。 IsBusyのチェックとCancelAsyncの呼び出しからなる操作はアトミックではありません。幸いにもDownloadStringCompletedはUIスレッドにディスパッチされるので、同期について心配する必要はありません。下のスニペットは、どのように達成できるかを示しています。簡単にするため、Windowsフォームです。

public partial class Form1 : Form 
{ 
    WebClient _WebClient; 
    bool _UpdateNews; 

    public Form1() 
    { 
     InitializeComponent(); 
     _WebClient = new WebClient(); 
     _WebClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(_WebClient_DownloadStringCompleted); 
     _UpdateNews = false; 
    } 

    void _WebClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) 
    { 
     if (_UpdateNews) 
     { 
      _UpdateNews = false; 
      UpdateNews(); 
     } 
     else if (e.Error != null) 
     { 
      // Report error 
     } 
     else 
     { 
      MessageBox.Show(e.Result); 
     } 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     if (_WebClient.IsBusy) 
     { 
      _WebClient.CancelAsync(); 
      _UpdateNews = true; 
     } 
     else 
     { 
      UpdateNews(); 
     } 
    } 

    private void UpdateNews() 
    { 
     _WebClient.DownloadStringAsync(new Uri("http://stackoverflow.com/questions/7084948/c-concurrent-i-o-operations-exception")); 
    } 
} 
+0

ご理解いただきありがとうございます。 – FrankCap

+0

現在の操作をキャンセルする唯一の理由がリフレッシュである場合は、_UpdateNewsフィールドを削除し、代わりにe.Cancelledを使用することができます。私はそれをより一般的なものにするために私の中に入れなかった。 – StanislawSwierc