0

我正在从网上下载两个 JSON 文件,之后我想允许加载两个页面,但不是之前。但是,ManualResetEvent为了加载页面而需要设置的 永远不会“触发”。即使我知道它被设置了,WaitOne也永远不会返回。

启动下载的方法:

private void Application_Launching(object sender, LaunchingEventArgs e)
{
    PhoneApplicationService.Current.State["doneList"] = new List<int>();
    PhoneApplicationService.Current.State["manualResetEvent"] = new ManualResetEvent(false);

    Helpers.DownloadAndStoreJsonObject<ArticleList>("http://arkad.tlth.se/api/get_posts/", "articleList");
    Helpers.DownloadAndStoreJsonObject<CompanyList>("http://arkad.tlth.se/api/get_posts/?postType=webbkatalog", "catalog");
}

下载方法,设置ManualResetEvent

public static void DownloadAndStoreJsonObject<T>(string url, string objName)
{
    var webClient = new WebClient();
    webClient.DownloadStringCompleted += (sender, e) => 
    {
        if (!string.IsNullOrEmpty(e.Result))
        {
            var obj = ProcessJson<T>(e.Result);
            PhoneApplicationService.Current.State[objName] = obj;


            var doneList = PhoneApplicationService.Current.State["doneList"] as List<int>;
            doneList.Add(0);

            if (doneList.Count == 2)    // Two items loaded
            {
                (PhoneApplicationService.Current.State["manualResetEvent"] as ManualResetEvent).Set();  // Signal that it's done
            }
        }
    };

    webClient.DownloadStringAsync(new Uri(url));
}

等待方法(本例中的构造函数)

public SenastePage()
{
    InitializeComponent();

    if ((PhoneApplicationService.Current.State["doneList"] as List<int>).Count < 2)
    {
        (PhoneApplicationService.Current.State["manualResetEvent"] as ManualResetEvent).WaitOne();
    }
    SenasteArticleList.ItemsSource =  (PhoneApplicationService.Current.State["articleList"] as ArticleList).posts;
}

如果我在尝试访问该构造函数之前等待,它很容易通过 if 语句并且不会被捕获WaitOne,但是如果我立即调用它,我会卡住,并且永远不会返回......

有任何想法吗?

4

2 回答 2

1

必须不惜一切代价防止阻塞 UI 线程。特别是在下载数据时:不要忘记您的应用程序正在手机上执行,手机的网络非常不稳定。如果加载数据需要两分钟,则 UI 将冻结两分钟。这将是一个糟糕的用户体验。

有很多方法可以防止这种情况。例如,您可以保持相同的逻辑,但在后台线程而不是 UI 线程中等待:

public SenastePage()
{
    // Write the XAML of your page to display the loading animation per default
    InitializeComponent();

    Task.Factory.StartNew(LoadData);
}

private void LoadData()
{
    ((ManualResetEvent)PhoneApplicationService.Current.State["manualResetEvent"]).WaitOne();

    Dispatcher.BeginInvoke(() =>
    {
        SenasteArticleList.ItemsSource = ((ArticleList)PhoneApplicationService.Current.State["articleList"]).posts;

        // Hide the loading animation
    }
}

这只是一种快速而肮脏的方式来达到你想要的结果。您还可以使用任务重写代码,并Task.WhenAll在它们全部完成时触发操作。

于 2013-10-20T19:07:46.993 回答
0

也许有一个逻辑问题。doneList在 SenastePage() 构造函数中,只有当计数小于 2时,您才等待设置事件。doneList但是,在计数等于 2之前,您不会触发 set 事件。您正在侦听 set 事件,然后它才能触发。

于 2013-10-20T18:51:16.720 回答