Вот как я подхожу к решению этой проблемы.
Ваш ViewModel реализует INotifyPropertyChanged, верно?Там нет необходимости отправлять события.Просто поднимите их «голыми» в модели, затем отправьте RaisePropertyChanged во ViewModel.
И да, у вас должна быть какая-то модель / база данных синглтона в вашем коде.В конце концов, что такое база данных SQL, если не какой-то гигантский синглтон?Поскольку у нас нет базы данных в WP7, не стесняйтесь создавать одноэлементный объект.У меня есть один, который называется «База данных»:)
Я только что попытался добавить туда потоки данных и понимаю, что на самом деле лучший подход - просто реализовать INotifyPropertyChanged прямо на уровне модели. Нет ничего постыдного в этом .
Итак, вот что я делаю в объекте-базе данных singleton, чтобы загрузить и вернуть мою "таблицу" Tours (обратите внимание на thread.sleep, чтобы сделатьзагрузка занимает видимое время, обычно его саб 100 мс).Класс базы данных теперь реализует INotifyPropertyChanged и вызывает события, когда загрузка завершена:
public ObservableCollection<Tour> Tours
{
get
{
if ( _tours == null )
{
_tours = new ObservableCollection<Tour>();
ThreadPool.QueueUserWorkItem(LoadTours);
}
return _tours;
}
}
private void LoadTours(object o)
{
var start = DateTime.Now;
//simlate lots of work
Thread.Sleep(5000);
_tours = IsoStore.Deserialize<ObservableCollection<Tour>>( ToursFilename ) ?? new ObservableCollection<Tour>();
Debug.WriteLine( "Deserialize time: " + DateTime.Now.Subtract( start ).ToString() );
RaisePropertyChanged("Tours");
}
Вы подписаны?Я десериализирую список туров в фоновом потоке, затем вызываю событие, измененное свойством.
Теперь в ViewModel я хочу привязать список TourViewModels, который я выбираю с помощью запроса linq, как только вижу, чтоТаблица туров изменилась.Вероятно, это немного дешево для прослушивания события Database во ViewModel - это может быть «лучше» для инкапсуляции этого в модели, но давайте не будем делать работу, нам не нужно, а?
ПодцепитьСобытие базы данных в конструкторе Viewmodel:
public TourViewModel()
{
Database.Instance.PropertyChanged += DatabasePropertyChanged;
}
Прослушайте соответствующее изменение таблицы (нам нравятся волшебные строки! ;-)):
private void DatabasePropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(e.PropertyName == "Tours")
{
LoadTourList();
}
}
Выберите нужные записи из таблицы, затем сообщите представлению, что есть новые данные:
public void LoadTourList()
{
AllTours = ( from t in Database.Instance.Tours
select new TourViewModel( t ) ).ToList();
RaisePropertyChanged( "AllTours" );
}
И, наконец, в вашей ViewModelBase лучше всего проверить, нужно ли диспетчеризовать ваш RaisePropertyChanged.Мой метод «SafeDispatch» в значительной степени такой же, как и метод MVVMlight:
private void RaisePropertyChanged(string property)
{
if ( PropertyChanged != null )
{
UiHelper.SafeDispatch(() =>
PropertyChanged(this, new PropertyChangedEventArgs(property)));
}
}
Это прекрасно работает в моем коде, и я думаю, что это довольно аккуратно?
Наконец, дополнительно для экспертов: в WP7 было бы неплохо добавить ProgressBar с IsIndeterminate = True для вашей страницы - при этом отобразится «пунктирная» строка прогресса.Тогда, что вы можете сделать, это при первой загрузке ViewModel вы можете установить для свойства «ProgressBarVisible» значение Visible (и вызвать соответствующее событие PropertyChanged).Привязать видимость ProgressBar к этому свойству ViewModel.Когда событие Database PropertyChanged сработает, установите видимость Collapsed, чтобы индикатор прогресса исчез.
Таким образом, пользователь будет видеть индикатор выполнения «IsIndeterminate» в верхней части экрана во время выполнения десериализации.Nice!