我在WP7应用程序中有一个刷新按钮来更新新闻。当我双击或三重点击刷新按钮,我得到一个错误
"WebClient does not support concurrent I/O operations" .
我认为那是因为它发送请求三次,使它崩溃。这是我的点击代码。
private void NewsRefresh_Click(object sender, RoutedEventArgs e)
{
var vm = this.DataContext as MainPageViewModel;
if (vm != null)
{
vm.UpdateNews();
}
}
如何设置为"if it is busy cancel the process"
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"));
}
}
最简单的方法(虽然不是防弹):
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之前,您需要检查是否已经在使用它。当多个线程可能在单个实例上操作时,或者如果您进行多个操作(UpdateNews除外),则会出现问题。当涉及到多个线程时,最简单的方法是用互斥锁包围WebClient的使用。
当然,另一种选择是不重用WebClient实例,而是为每个新请求创建一个新实例。
好吧,好吧,使用DownloadStringAsync肯定会让事情变得有趣。除非您移动重新启用的代码,否则禁用UI将不起作用。最简单的方法是按照我最后的建议创建一个WebClient的新实例。我自己不是很喜欢WebClient,更喜欢使用WebRequest.Create.