Ожидание ручного сброса события не сбрасывается после установки
Я загружаю два файла 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 ответа
Блокировка потока пользовательского интерфейса должна быть предотвращена любой ценой. Особенно при загрузке данных: не забывайте, что ваше приложение выполняется на телефоне, который имеет очень нестабильную сеть. Если загрузка данных занимает две минуты, пользовательский интерфейс будет заблокирован на две минуты. Это был бы ужасный пользовательский опыт.
Есть много способов предотвратить это. Например, вы можете сохранить ту же логику, но ждать в фоновом потоке вместо потока пользовательского интерфейса:
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
вызвать действие, когда они все закончены.
Возможно, есть логическая проблема. В конструкторе SenastePage() вы ожидаете события set, только если doneList
количество меньше двух. Однако вы не запускаете установленное событие, пока doneList
количество равно двум. Вы слушаете установленное событие до того, как оно может сработать.