设置后,ManualResetEvent等待不释放

时间:2013-10-20 18:35:01

标签: c# .net asynchronous windows-phone-8 manualresetevent

我正在从网上下载两个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捕获,但是如果我立即调用它,我会卡住,它永远不会返回。 ..

有什么想法吗?

2 个答案:

答案 0 :(得分: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触发操作。

答案 1 :(得分:0)

也许存在逻辑问题。在SenastePage()构造函数中,仅当doneList计数小于2时才等待set事件。但是,在doneList计数等于2之前,不会触发set事件。你正在聆听set事件,然后才能开火。