在ViewModel上引发PropertyChangedEvent后,ListView没有刷新

时间:2013-11-23 17:26:33

标签: c# wpf listview mvvm binding

我正在尝试创建一个文件资源管理器样式的TreeView / ListView窗口,允许用户从“ProjectFolder”中选择“项目”。

“ProjectFolder”树绑定到我的ViewModel上名为“RootProjectFolders”的属性,“Project”列表绑定到名为“ProjectsInSelectedFolder”的属性。事情主要是工作;但是,当我第一次加载窗口时,我得到了null异常,因为尚未设置“SelectedFolder”。当我尝试执行简单检查以确保“SelectedFolder”不为null时,我的“Project”ListView停止刷新。

if ((this.SelectedFolder != null) && (this.SelectedFolder.ProjectFolder.Projects != null))
{
   foreach (Project project in this.SelectedFolder.ProjectFolder.Projects)
   {
      _projectsInSelectedFolder.Add(new ProjectViewModel(project));
   }
}
base.RaisePropertyChangedEvent("ProjectsInSelectedFolder");

如果从上面删除(this.SelectedFolder != null),ListView将更新,但我将收到NullException错误。为什么检查会破坏我的约束力?

跟进有关其他信息的请求,这里是TreeView和ListView的XAML,它们绑定到ViewModel上的属性:

<TreeView Name="treeviewProjectFolders" Grid.Column="0"
            ItemsSource="{Binding Path=RootProjectFolders}">
            <TreeView.ItemContainerStyle>
                <Style TargetType="{x:Type TreeViewItem}">
                    <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
                    <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
                    <Setter Property="FontWeight" Value="Normal" />
                    <Style.Triggers>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter Property="FontWeight" Value="Bold" />
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </TreeView.ItemContainerStyle>
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate 
                    ItemsSource="{Binding Children}">
                    <TextBlock Text="{Binding Path=Name}" />
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
        <GridSplitter Name="splitterProjects" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
        <ListView Name="listviewProjects" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
            ItemsSource="{Binding Path=ProjectsInSelectedFolder}">
            <ListView.ItemContainerStyle>
                <Style TargetType="{x:Type ListViewItem}">
                    <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}" />
                </Style>
            </ListView.ItemContainerStyle>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Path=Name}" />
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

这是ViewModel

public class SelectProjectViewModel : ViewModelBase
{
    #region Fields
    List<ProjectViewModel> _projectsInSelectedFolder;
    List<ProjectFolderViewModel> _rootProjectFolders;
    static ProjectFolderViewModel _selectedFolder = null;
    ProjectViewModel _selectedProject;
    #endregion // Fields

    #region Constructor
    public SelectProjectViewModel(ProjectFolders rootProjectFolders)
    {
        if (_rootProjectFolders != null) { _rootProjectFolders.Clear(); }            
        _rootProjectFolders = new List<ProjectFolderViewModel>();
        foreach (ProjectFolder rootFolder in rootProjectFolders)
        {
            _rootProjectFolders.Add(new ProjectFolderViewModel(rootFolder, this));
        }
        _projectsInSelectedFolder = new List<ProjectViewModel>();
        // Subscribe to events
        this.PropertyChanged += OnPropertyChanged;
    }
    #endregion // Constructor

    #region Properties
    public List<ProjectFolderViewModel> RootProjectFolders
    {
        get
        {
            return _rootProjectFolders;
        }
    }        
    public List<ProjectViewModel> ProjectsInSelectedFolder
    {
        get
        {                
            return _projectsInSelectedFolder;
        }
    }
    public ProjectFolderViewModel SelectedFolder
    {
        get 
        { 
            return _selectedFolder; 
        }
        set
        {
            if (_selectedFolder != value)
            {
                _selectedFolder = value;
            }
        }
    }
    public ProjectViewModel SelectedProject
    {
        get
        {
            return _selectedProject;
        }
        set
        {
            _selectedProject = value;
            base.RaisePropertyChangedEvent("SelectedProject");
        }
    }
    #endregion // Properties

    #region Methods
    public void FindSelectedFolder(ProjectFolderViewModel root)
    {
        if (root.IsSelected) { _selectedFolder = root; }
        else
        {
            foreach (ProjectFolderViewModel folder in root.Children)
            {
                if (_selectedFolder == null)
                {
                    FindSelectedFolder(folder);
                }
            }
        }            
    }
    #endregion // Methods

    #region Event Handlers
    void OnPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        switch (e.PropertyName)
        {
            case "SelectedFolder":
                _selectedFolder = null;
                foreach (ProjectFolderViewModel root in this.RootProjectFolders)
                {
                    if (_selectedFolder == null)
                    {
                        this.FindSelectedFolder(root);
                    }
                }
                _projectsInSelectedFolder.Clear();
                if ((this.SelectedFolder != null) && (this.SelectedFolder.ProjectFolder.Projects != null))
                {
                    foreach (Project project in this.SelectedFolder.ProjectFolder.Projects)
                    {
                        _projectsInSelectedFolder.Add(new ProjectViewModel(project));
                    }
                }
                base.RaisePropertyChangedEvent("ProjectsInSelectedFolder");
                break;
        }
    }
    #endregion // Event Handlers

此外,这里是用于提升“SelectedFolder”属性的各个项目文件夹的ViewModel:

public class ProjectFolderViewModel : ViewModelBase
{
    #region Fields
    ReadOnlyCollection<ProjectFolderViewModel> _children;
    List<ProjectFolderViewModel> _childrenList;
    bool _isExpanded;
    bool _isSelected;
    ProjectFolderViewModel _parentNode;
    SelectProjectViewModel _parentTree;
    ProjectFolder _projectFolder;        
    #endregion // Fields

    #region Constructor
    public ProjectFolderViewModel(ProjectFolder projectFolder, SelectProjectViewModel parentTree) : this(projectFolder, parentTree, null)
    { }
    private ProjectFolderViewModel(ProjectFolder projectFolder, SelectProjectViewModel parentTree, ProjectFolderViewModel parentNode)
    {
        _projectFolder = projectFolder;
        _parentTree = parentTree;
        _parentNode = parentNode;
        _childrenList = new List<ProjectFolderViewModel>();
        foreach (ProjectFolder child in _projectFolder.ChildFolders)
        {
            _childrenList.Add(new ProjectFolderViewModel(child, _parentTree));
        }
        _children = new ReadOnlyCollection<ProjectFolderViewModel>(_childrenList);
    }
    #endregion // Constructor

    #region Properties
    public ReadOnlyCollection<ProjectFolderViewModel> Children
    {
        get
        {
            return _children;
        }
    }
    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 && _parentNode != null)
                _parentNode.IsExpanded = true;
        }
    }
    public bool IsSelected
    {
        get
        {
            return _isSelected;
        }
        set
        {
            _isSelected = value;
            base.RaisePropertyChangedEvent("IsSelected");
            //if (_isSelected)
            //{ 
                _parentTree.RaisePropertyChangedEvent("SelectedFolder");
            //}
        }
    }
    public string Name
    {
        get
        {
            return _projectFolder.Name;
        }
    }
    public ProjectFolder ProjectFolder
    {
        get
        {
            return _projectFolder;
        }
    }
    #endregion // Properties

1 个答案:

答案 0 :(得分:0)

更改所有

List<T> to observablecollection<T>

因为当你有新的文件或文件夹添加Item时,你没有创建新的List,因为observablecollection实现了INotifyCollectionChanged,而INotifyPropertyChanged它将在内部负责通知和刷新View。但列表不能这样做