У меня есть приложение WPF, использующее MVVM, которое использует TreeViewItemViewModels для упрощения работы с древовидной структурой, как продемонстрировал Джош Смит http://www.codeproject.com/KB/WPF/TreeViewWithViewModel.aspx
Мое древовидное представление представляет записи в реляционной базе данных, и каждый узел имеет своих дочерних элементов, загружаемых по требованию. Чтобы улучшить отзывчивость пользовательского интерфейса, я пытался загрузить данные асинхронно, используя Задачи в .net 4.0, но изо всех сил стараюсь реализовать это удовлетворительно.
Свойство treeviewitemviewmodel IsExpanded выглядит так:
public bool IsExpanded
{
get { return _isExpanded; }
set
{
if (_isExpanded == value)
return;
if (!_isSelected)
IsSelected = true;
_isExpanded = value;
if (_isExpanded &&
_parent != null &&
_parent.GetType() != typeof(FirstGenerationViewModel))
_parent.IsExpanded = true;
ApplicationSetup.Messenger.NotifyColleagues(ApplicationSetup.MSG_WORKING, true);
Task task = Task.Factory.StartNew(() =>
{
LoadChildren();
})
.ContinueWith((t) =>
{
this.OnPropertyChanged("IsExpanded");
ApplicationSetup.Messenger.NotifyColleagues(ApplicationSetup.MSG_WORKING, false);
}, ApplicationSetup.UIScheduler);
}
}
Если я выбираю элементы вручную, раскрываю и сворачиваю их, все работает должным образом - отображается рабочая анимация, пока выполняется LoadChildren (), а затем элементы расширяются, когда вызывается OnPropertyChanged и анимация закрывается.
Однако я пытаюсь реализовать функцию поиска. Если запись уже загружена, я просто перебираю древовидное представление, пока оно не будет найдено, и затем выбираю его. Однако, если он не загружен, процесс должен выполнить поиск в базе данных, а затем отобразить ее. Поскольку записи загружаются по требованию, процесс получает искомый элемент и его предков из БД и пытается развернуть каждого предка по очереди, затем, наконец, выбирает искомый элемент:
foreach (var item in ancestors.Keys)
{
TreeViewItemViewModel tv = _fgvm.recordsViewHelper.GetTreeViewItem(new ItemArgs
{
TargetTableName = item,
TargetPk = ancandtarget[item]
});
tv.IsExpanded = true;
}
Если искомый элемент находится высоко в иерархии, это работает. Тем не менее, когда запись вложена в несколько элементов, tv становится нулевым. Я думаю, это потому, что элемент не был загружен до того, как _fgvm.recordsViewHelper.GetTreeViewItem пытается найти его в древовидном представлении.
Как я могу это сделать? Я пытался использовать Wait (), но кажется, что пользователь зависает.