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打开一个项目时,我的属性上的断点确实触发并引发一个事件。

任何想法?

PropertyChanged always null with TreeView

这个解决方案以一种更加mvvm友好的方式解决了这个问题。一个UserControl包含一个TreeView。它使用YourViewModel类型作为数据上下文。视图模型包含一个YourDomainType的集合,它本身有一个相同类型的子集合ChildElements

在xaml中,数据绑定到视图模型的ElementInViewModel集合。此外,还有一个HierarchicalDataTemplate(这是适合于树视图)。

类型YourDomainType包含属性IsExpandedIsSelected,它们分别与StyleTreeViewItem的属性绑定。如果您在视图模型中设置了这些属性,树视图应该按照预期做出反应(选择或展开各自的TreeViewItem)。

我知道IsExpandedIsSelected不属于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;
}