我正在从网上下载两个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
捕获,但是如果我立即调用它,我会卡住,它永远不会返回。 ..
有什么想法吗?
答案 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事件,然后才能开火。