Я прочитал несколько статей здесь, в которых описывается, как слушать уведомления, поднятые. Однако: у меня все еще есть проблема с тем, чтобы применить их к моей заявке.Уведомить родителя ViewModel изменений в дочернихМодель просмотра
В настоящее время у меня есть приложение с несколькими «страницами».
Одна из страниц содержит элемент управления TreeView WPF, а также несколько моделей ViewModels и данных.
public class FoldersSearchViewModel
{
private ReadOnlyCollection<DriveTreeViewItemViewModel> _drives;
public FoldersSearchViewModel(string[] logicalDrives)
{
_drives = new ReadOnlyCollection<DriveTreeViewItemViewModel>(
Environment.GetLogicalDrives()
.Select(s => new DriveInfo(s))
.Where(di => di.IsReady)
.Select(di => new DriveTreeViewItemViewModel(di))
.ToList()
);
}
public ReadOnlyCollection<DriveTreeViewItemViewModel> Drives
{
get { return _drives; }
}
}
Эта модель представления содержит DriveTreeViewItemViewModels и связанный через DataContext к UserControl ("страницы").
Классы диск- и DirectoryTreeViewItemViewModel содержат несколько атрибутов, но в противном случае на основе TreeViewItemViewModel, который вы можете увидеть здесь:
public class TreeViewItemViewModel : INotifyPropertyChanged
{
#region Data
static readonly protected TreeViewItemViewModel DummyChild = new TreeViewItemViewModel();
readonly ObservableCollection<TreeViewItemViewModel> _children;
readonly TreeViewItemViewModel _parent;
bool _isExpanded;
bool _isSelected;
#endregion // Data
#region Constructors
protected TreeViewItemViewModel(TreeViewItemViewModel parent, bool lazyLoadChildren)
{
_parent = parent;
_children = new ObservableCollection<TreeViewItemViewModel>();
if (lazyLoadChildren)
_children.Add(DummyChild);
}
// This is used to create the DummyChild instance.
private TreeViewItemViewModel()
{
}
#endregion // Constructors
#region Presentation Members
#region Children
/// <summary>
/// Returns the logical child items of this object.
/// </summary>
public ObservableCollection<TreeViewItemViewModel> Children
{
get { return _children; }
}
#endregion // Children
#region HasLoadedChildren
/// <summary>
/// Returns true if this object's Children have not yet been populated.
/// </summary>
public bool HasDummyChild
{
get { return this.Children.Count == 1 && this.Children[0] == DummyChild; }
}
#endregion // HasLoadedChildren
#region IsExpanded
/// <summary>
/// Gets/sets whether the TreeViewItem
/// associated with this object is expanded.
/// </summary>
public bool IsExpanded
{
get { return _isExpanded; }
set
{
if (value != _isExpanded)
{
_isExpanded = value;
this.OnPropertyChanged("IsExpanded");
}
// Expand all the way up to the root.
if (_isExpanded && _parent != null)
_parent.IsExpanded = true;
// Lazy load the child items, if necessary.
if (this.HasDummyChild)
{
this.Children.Remove(DummyChild);
this.LoadChildren();
}
}
}
#endregion // IsExpanded
#region IsSelected
/// <summary>
/// Gets/sets whether the TreeViewItem
/// associated with this object is selected.
/// </summary>
public bool IsSelected
{
get { return _isSelected; }
set
{
if (value != _isSelected)
{
_isSelected = value;
this.OnPropertyChanged("IsSelected");
}
}
}
#endregion // IsSelected
#region LoadChildren
/// <summary>
/// Invoked when the child items need to be loaded on demand.
/// Subclasses can override this to populate the Children collection.
/// </summary>
protected virtual void LoadChildren()
{
}
#endregion // LoadChildren
#region Parent
public TreeViewItemViewModel Parent
{
get { return _parent; }
}
#endregion // Parent
#endregion // Presentation Members
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion // INotifyPropertyChanged Members
}
Я последовал за учебник и идеи, описанные в http://www.codeproject.com/Articles/26288/Simplifying-the-WPF-TreeView-by-Using-the-ViewMode и все прекрасно работает так далеко.
Моя проблема: Я хотел бы добавить строку «selected» в качестве атрибута FoldersSearchViewModel, которая будет содержать путь к выбранному дочернему ViewModel. Модели DriveTreeViewItemViewModel и DirectoryTreeViewItemViewModel имеют свойство Path, содержащее полный путь к дочернему элементу.
Итак: однажды вызывается OnPropertyChanged («IsSelected»), я хотел бы уведомить об этом FoldersSearchViewModel и передать метод Path-property из выбранного TreeViewItemViewModel в новый атрибут «selected» (string).
я мог бы добиться этого, передавая FoldersSearchViewModel-объект к детям и внукам и т.д. в конструкторе - но там нет лучшего способа сделать это? Я предполагаю, что я должен привязать FoldersSearchViewModel к событию PropertyChanged каждого узла и подузла, но я хотел бы знать, что кто-то с опытом работы в MVVM будет делать в таком случае.
К слову: я мог бы использовать WPF Treeview.SelectedItem для получения выбранного в данный момент TreeViewItemViewModel, но это звучит не так, поскольку я хочу, чтобы представление, модели и модели отображались отдельно.
P.s .: Я пробовал читать и использовать MVVM in WPF - How to alert ViewModel of changes in Model... or should I?, но, к сожалению, это не похоже на мою проблему.
Любая помощь очень ценится!
Да, это так. Я использую нечто подобное; однако: у меня не было сообщений-объектов, которые я отправлял, но вместо этого я отправил ключ типа propertyName, а также связанный с ним объект. Я верю, что в конечном итоге сообщения, которые реализуют IMessageBase, будут лучше, потому что они могут содержать любое количество отдельных атрибутов. Спасибо. Мне кажется, теперь я понимаю, как заставить его работать (хотя я не использую инъекцию зависимости). – Igor