1

我的 Silverlight 项目中有这段代码:

private void button1_Click(object sender, RoutedEventArgs e)
{
    string baseUri = "http://foo.bar";
    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri(baseUri));
    request.BeginGetResponse(new AsyncCallback(ReadCallback),request);
}
private void ReadCallback(IAsyncResult asynchronousResult)
{
    HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
    HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
    using (StreamReader streamReader1 = new StreamReader(response.GetResponseStream()))
    {
        string resultString = streamReader1.ReadToEnd();
        MessageBox.Show(resultString);
    }
}

当我运行代码时,我得到以下异常:

unauthorizedaccessexception
Invalid cross-thread access.

我认为这是返回的字符串有问题。但是,即使我这样说:

MessageBox.Show("foobar");

同样的例外上升。我认为问题来自无法执行此类操作的 ReadCallback 函数。

你能帮助我吗?

谢谢,

问候

4

1 回答 1

4

我认为这是因为 Silverlight 的某些部分不能由代码调用,而必须源自用户输入;我认为 MessageBox 属于这一类。因此,除非由于用户按下按钮或超链接而调用 MessageBox,否则它不会起作用。

请注意,它不必在按钮或超链接单击事件的处理程序中;调用层次结构进一步向下的任何地方都有效。例如,当由于异步服务调用而需要启动此类操作时,我基本上所做的是显示一个 ChildWindow,其中包含一个超链接,上面写着“单击此处打开您的 x”或用户尝试执行的任何操作(我我想我用它来打开服务器生成的 PDF 或类似文件)。

此外,如果 MessageBox 确实可以在没有我刚刚写过的所有问题的情况下被调用,则可以通过调用 Dispatcher.Invoke 或 Dispatcher.BeginInvoke 并传递一个执行实际操作的委托来解决跨线程访问异常。这是因为异步操作(显然)发生在单独的线程中,但 Silverlight 与 WPF 和之前的 WinForms 一样,只需要从一个线程访问其控件;使用控件的 Dispatcher 调用会将操作委托给正确的线程。

要使用 BeginInvoke 解决方案,试试这个而不是简单地调用 MessageBox.Show:

string resultString = streamReader1.ReadToEnd();
Dispatcher.Invoke(new Action(() => MessageBox.Show("")));

假设代码位于 Control 代码隐藏(UserControl、Window 等)中,因此 Dispatcher 属性可用。如果您希望用户界面有时间正确更新自身,则可以使用 BeginInvoke 而不是 Invoke,但通常差异是难以察觉的。

于 2010-09-21T15:45:25.700 回答