PropertyChanged always null with TreeView
本文关键字:TreeView with null always PropertyChanged | 更新日期: 2023-09-27 17:55:05
我在WPF项目的TreeView中实现搜索功能时遇到了问题。
我用这个指南创建了一个带有ViewModels的TreeView。我已经使用TextSeachDemo和编辑控件的方式,他们认为他们适合我的应用程序。(添加正确的类,更多的层等)一切都很好,我得到了一个正确的子节点和父节点的结构,搜索函数也工作了,因为它找到了正确的条目。
现在的问题是:当我试图设置"IsExpanded"属性从代码什么都没有发生。调试显示RaiseProperty Changed方法中的PropertyChanged事件总是空的。
在Josh Smith提供的测试项目中,一切似乎都很好。我能看出的唯一显著区别是,他在代码中设置了数据上下文,而我在XAML:
中设置了数据上下文。Josh Smith的代码:
public TextSearchDemoControl()
{
InitializeComponent();
// Get raw family tree data from a database.
Person rootPerson = Database.GetFamilyTree();
// Create UI-friendly wrappers around the
// raw data objects (i.e. the view-model).
_familyTree = new FamilyTreeViewModel(rootPerson);
// Let the UI bind to the view-model.
base.DataContext = _familyTree;
}
来自MainViewModel(处理整个窗口的ViewModel)的构造函数
List<FactoryItem> rootItems = _machineService.GetFactoryItems();
FactoryTree = new FactoryTreeViewModel(rootItems);
其中FactoryTree是一个公共可观察属性,它绑定了TreeView的DataContext(而不是像上面那样在代码中):
<TreeView DataContext="{Binding FactoryTree}" ItemsSource="{Binding FirstGeneration}">
另一种方式,当我通过GUI打开一个项目时,我的属性上的断点确实触发并引发一个事件。
任何想法?
这个解决方案以一种更加mvvm友好的方式解决了这个问题。一个UserControl
包含一个TreeView
。它使用YourViewModel
类型作为数据上下文。视图模型包含一个YourDomainType
的集合,它本身有一个相同类型的子集合ChildElements
。
在xaml中,数据绑定到视图模型的ElementInViewModel
集合。此外,还有一个HierarchicalDataTemplate
(这是适合于树视图)。
类型YourDomainType
包含属性IsExpanded
和IsSelected
,它们分别与Style
中TreeViewItem
的属性绑定。如果您在视图模型中设置了这些属性,树视图应该按照预期做出反应(选择或展开各自的TreeViewItem
)。
我知道IsExpanded
和IsSelected
不属于DTO对象。YourDomainType
可能更多的是用于显示数据的类型,但它也可以包装存储在其中的DTO对象。
<UserControl>
<UserControl.DataContext>
<YourViewModel/>
</UserControl.DataContext>
<UserControl.Resources>
<CollectionViewSource Source="{Binding Path=ElementsInViewModel}" x:Key="Cvs">
</CollectionViewSource>
<HierarchicalDataTemplate DataType="{x:Type DomainModel:YourDomainType}"
ItemsSource="{Binding Path=ChildElements}">
<TextBlock Text="{Binding Path=Name}"/>
</HierarchicalDataTemplate>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
</Setter>
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
</Setter>
</Style>
</UserControl.Resources>
<DockPanel>
<TreeView ItemsSource="{Binding Source={StaticResource Cvs}}"/>
</DockPanel>
</UserControl>
public class YourViewModel
{
public ObservableCollection<YourDomainType> ElementsInViewModel
{
get
{
return _elementsInViewModel;
}
set
{
if (_elementsInViewModel != value)
{
_elementsInViewModel = value;
RaisePropertyChanged("ElementsInViewModel");
}
}
}
ObservableCollection<YourDomainType> _elementsInViewModel;
public YourViewModel()
{
}
}
public class YourDomainType
{
public ObservableCollection<YourDomainType> ChildElements
{
get
{
return _childElements;
}
set
{
if (_childElements != value)
{
_childElements = value;
RaisePropertyChanged("ChildElements");
}
}
}
ObservableCollection<YourDomainType> _childElements;
public bool IsExpanded
{
get
{
return _isExpanded;
}
set
{
if (_isExpanded != value)
{
_isExpanded = value;
RaisePropertyChanged("IsExpanded");
}
}
}
bool _isExpanded;
public bool IsSelected
{
get
{
return _isSelected;
}
set
{
if (_isSelected != value)
{
_isSelected = value;
RaisePropertyChanged("IsSelected");
}
}
}
bool _isSelected;
public string Name
{
get
{
return _name;
}
set
{
if (_name != value)
{
_name = value;
RaisePropertyChanged("Name");
}
}
}
string _name;
}