UI未在异步Web请求回调中更新

时间:2010-07-13 04:56:37

标签: windows-phone-7

我正在使用它来发送网页请求并下载一些数据:

public partial class MainPage : PhoneApplicationPage
{
    public MainPage()
    {
        InitializeComponent();

        var client = new WebClient();

        client.DownloadStringCompleted += (s, e) => {
            textBlock1.Text = e.Result;
        };

        client.DownloadStringAsync(new Uri("http://example.com"));
    }
}

即使textBlock1包含正确的数据,e.Result的文字也不会发生变化。如何从回调中更新?

编辑:如果我在回调中添加MessageBox.Show(e.Result);以及textBlock1.Text分配,则消息框和文本框都会显示正确的数据。

再次编辑:如果我添加一个TextBox并在行textBlock1.Text行之后设置它的文本,它们都会显示正确的文本。

6 个答案:

答案 0 :(得分:4)

我认为,这是一个错误。

答案 1 :(得分:2)

我还遇到了一些从不同调度员更新UI的问题。我最后做的是使用TextBlock(或其他UI元素)自己的调度程序,这对我有用。我认为手机框架可能在应用程序和UI元素之间使用不同的调度程序。注意从dispatcher.BeginInvoke到textbox1.Dispatcher ...

的更改
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
    var dispatcher = Deployment.Current.Dispatcher;

    var client = new WebClient();

    client.DownloadStringCompleted += (s, e) =>
    {
        var result = e.Result;
        textBlock1.Dispatcher.BeginInvoke(
            ()=> textBlock1.Text = result
            );
    };

    client.DownloadStringAsync(new Uri("http://example.com"));
}

答案 2 :(得分:2)

从浏览WP7论坛,一群人报告说这与视频卡驱动程序问题有关。我已将ATI Radeon HD 3400驱动程序更新到最新版本,它现在似乎正常运行。

答案 3 :(得分:1)

client.DownloadStringAsync期待像这样的Uri:

client.DownloadStringAsync(new Uri("http://example.com"));

另外,你不应该像这样通过Dispatcher.BeginInvoke更新你的TextBlock:

    client.DownloadStringCompleted += (s, e) => 
    { 
        if (null == e.Error) 
            Dispatcher.BeginInvoke(() => UpdateStatus(e.Result)); 
        else 
            Dispatcher.BeginInvoke(() => UpdateStatus("Operation failed: " + e.Error.Message)); 
    };

答案 4 :(得分:1)

public partial class MainPage : PhoneApplicationPage
{
    public MainPage()
    {
        InitializeComponent();

        Loaded += MainPage_Loaded;
    }

    void MainPage_Loaded(object sender, RoutedEventArgs e)
    {
        var dispatcher = Deployment.Current.Dispatcher;

        var client = new WebClient();

        client.DownloadStringCompleted += (s, e) =>
        {
            var result = e.Result;
            dispatcher.BeginInvoke(
                ()=> textBlock1.Text = result
                );
        };

        client.DownloadStringAsync(new Uri("http://example.com"));
    }
}

答案 5 :(得分:1)

我想评论但还不能。是的,我有一个非常类似的问题。在我的情况下,我的viewmodel是更新DownloadStatus属性,然后在下载完成后我做了一些工作并继续更新这个属性。

一旦ViewModel代码命中OpenReadCompleted方法,视图就会停止更新。我仔细研究了代码。 PropertyChanged触发,视图甚至返回并检索新属性值,但从不显示更改。

我确定这是一个错误,但后来我创建了一个全新的项目来重现这个问题,它运行正常!

这是我的非再现代码的片段。绑定到“DownloadStatus”的UI文本块很快就会正常更新。但是同样的范例在我的主项目中不起作用。真气!

public void BeginDownload(bool doWorkAfterDownload)
{
    DownloadStatus = "Starting ...";

    _doExtraWork = doWorkAfterDownload;
    var webClient = new WebClient();

    string auth = "Basic " + Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes("test:password"));
    webClient.Headers["Authorization"] = auth;

    webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged);
    webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient_OpenReadCompleted);

    webClient.OpenReadAsync(new Uri("http://www.ben.geek.nz/samsung1.jpg"));
}

void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
    if (e.Error != null)
    {
        DownloadStatus = e.Error.Message;
        return;
    }

    DownloadStatus = "Completed. Idle.";

    if(_doExtraWork)
    {
        Thread t = new Thread(DoWork);
        t.Start(e.Result);
    }

}

void DoWork(object param)
{
    InvokeDownloadCompleted(new EventArgs());

    // just do some updating
    for (int i = 1; i <= 10; i++)
    {
        DownloadStatus = string.Format("Doing work {0}/10", i);
        Thread.Sleep(500);
    }
    DownloadStatus = "Completed extra work. Idle.";
    InvokeExtraWorkCompleted(new EventArgs());
}