2

Я новичок в асинхронном программировании и WP8, это мое первое приложение, и у меня есть некоторые проблемы с Dispatcher.BeginInvoke (..)Windows Phone 8 Dispatcher.BeginInvoke не работает асинхронной

В моем коде позади зрения class, я пытаюсь загрузить данные в Pivot scree async для второй вкладки.

Вот что я имею сейчас:

public partial class ReminderPivot : PhoneApplicationPage 
    { 
     #region Reminder Members 
     private ReminderViewModel _model; 
     private IRepository _repository; 
     #endregion Reminder Members 

     #region Constructors 
     public ReminderPivot() 
     { 
      InitializeComponent(); 
      _model = new ReminderViewModel(); 
      _repository = new LocalStorageRepository(); 

      LoadData(); 
      LoadAsyncData(); 

      this.DataContext = _model; 

     } 
     #endregion Constructors 

     public void LoadData() 
     { 
      IEnumerable<Reminder> activeList = _repository.GetRemindersByStatusId(2); 
      if (activeList != null) 
      { 
       foreach (var reminder in activeList) 
       { 
        _model.ActiveReminders.Add(reminder); 
       } 
      } 
     } 
     public void LoadAsyncData() 
     {    
      Action action =() => 
      { 
       Thread.Sleep(5000); 

       IEnumerable<Reminder> inactiveList = _repository.GetRemindersByStatusId(3); 
       if (inactiveList != null) 
       { 
        _model.InctiveReminders = new System.Collections.ObjectModel.ObservableCollection<Reminder>(inactiveList); 
       } 
      }; 

      Dispatcher.BeginInvoke(action); 
     } 

Дело в том, что это по-прежнему блокирует мой UI поток. Что мне здесь не хватает?

EDIT: Идея состоит в том, чтобы загрузить данные async в ViewModel ObservableCollection, который является ModelBinded в XAML.

Если я попытаюсь сделать асинхронный вызов в другом потоке с помощью Task.Factory (...) и т.д., скажем, это сбой, поскольку я изменяю привязку из другого потока, а не потока пользовательского интерфейса.

+0

Я не вижу ничего в коде, который предполагает использование асинхронного ... 'Dispatcher.BeginInvoke' будет выполнять код в потоке пользовательского интерфейса, это только получение послан, чтобы быть выполненный позже! –

+0

Привет @PedroLamas. то вопрос в том, как я могу загрузить async? Если я попытаюсь с Task.Factory (..) и создать его в отдельном потоке, то он будет сбой, потому что мой список, который я обновляю, привязан к ListBox. –

+1

Мне кажется, что использование 'Task.Factory' является определенно лучшая возможность здесь ... –

ответ

2

После предложения @PedroLamas я заработал, не уверен, что это самый приятный способ или самый элегантный, но он выполняет свою работу.

Я делаю вызов, требующий времени, чтобы завершить другой поток с помощью Task.Factory и сделать его ожидаемым, и в конце просто обновите интерфейс пользователя Диспетчер.

public async void LoadAsyncDataWithTask() 
     { 
      IEnumerable<Reminder> inactiveList = null; 
      Action action =() => 
      { 
       Thread.Sleep(2000); 
       inactiveList = _repository.GetRemindersByStatusId(2); 
      }; 

      await Task.Factory.StartNew(action); 

      Action action2 =() => 
      { 
       if (inactiveList != null) 
       { 
        foreach(var item in inactiveList) 
        { 
         _model.InctiveReminders.Add(item); 
        } 
       } 
      }; 

      Dispatcher.BeginInvoke(action2); 

     } 
+1

Это будет работать (+1). Вы можете сделать немного лучше, сделав 'GetRemindersByStatusId' async, чтобы сохранить порядок вещей на этом уровне: это зависит от остальной части вашего кода. –

+1

В Windows Phone 8, я был в состоянии сделать что-то вроде этого размещения асинхронном перед лямбда: Dispatcher.BeginInvoke (асинхронном() => { ждут Task.Delay (125); TClock.RestTimerCanvas .Clear(); }); – Stonetip

1

Хотя то, что вы нашли работу и использование Task очень уточненный, с помощью Thread.Sleep вы по-прежнему блокируете поток в ThreadPool без причины.

Вы можете избежать этого, используя одноразовый System.Threading.Timer (see MSDN reference), который будет срабатывать на одном из (потоков) потоков ThreadPool. Затем используйте Dispatcher.BeginInvoke(...) в конце обратного вызова вашего таймера для обновления пользовательского интерфейса.

Например:

 var timer = new System.Threading.Timer(
      state => 
       { 
        // ... your code to run in background 

        // ... call BeginInvoke() when done 
        Dispatcher.BeginInvoke(() => MessageBox.Show("done")); 
       }, 
      null, 
      5000, 
      System.Threading.Timeout.Infinite); 
+0

Эй, Пол, спасибо за информацию, не знал, что +1. Thread.Sleep должен был просто проверить, работает ли этот метод (чтобы имитировать большее время загрузки, большую обработку данных, тяжелую работу и т. Д.). В производственном коде такого типа не существует: -p. –

Смежные вопросы