如何将TreeView绑定到ViewModel?

时间:2014-06-16 23:35:05

标签: c# xaml data-binding treeview viewmodel

我有一个视图模型如下:

public class SolutionViewModel : TreeViewItemViewModel {

    public ObservableCollection<TreeViewItemViewModel> Children {
        get { return mChildItems; }
    }

    public bool IsExpanded {
        get { return mIsExpanded; }
        set {
            if (value != mIsExpanded) {
                mIsExpanded = value;
                OnPropertyChanged("IsExpanded");
            }

            if (mIsExpanded && mParentItem != null)
                mParentItem.IsExpanded = true;

            if (this.HasDummyChild) {
                Children.Remove(EmptyItem);
                LoadChildren();
            }
        }
    }

    public bool IsSelected {
        get { return mIsSelected; }
        set {
            if (value != mIsSelected) {
                mIsSelected = value;
                OnPropertyChanged("IsSelected");
            }
        }
    }

    protected override void LoadChildren() {
        var subFolders = default(ReadOnlyCollection<Folder>);
        if (!GetSubFolders(mSolution.Folder.Name, out subFolders)) {
            subFolders = new ReadOnlyCollection<Folder>(new List<Folder>());
        }

        foreach (var folder in subFolders) {
            Children.Add(new SolutionItemViewModel(this, folder));
        }

    }

    public string SolutionName {
        get { return mSolution.Name; }
    }

}

TreeView的.Xaml如下:

<TreeView Name="SolutionTree" ItemsSource="{Binding SolutionViewModel}">
    <TreeView.ItemContainerStyle>
        <Style TargetType="{x:Type TreeViewItem}">
            <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
            <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
            <Style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="FontWeight" Value="Bold" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </TreeView.ItemContainerStyle>

    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type localmodels:SolutionViewModel}" 
                                  ItemsSource="{Binding Children}">
            <StackPanel Orientation="Horizontal">
                <Image Width="16" Height="16" Margin="3,0" Source="..\Resources\Folder_25x25.png" />
                <TextBlock Text="{Binding SolutionName}" />
            </StackPanel>
        </HierarchicalDataTemplate>
    </TreeView.Resources>
</TreeView>

SolutionExplorer

中选择文件后
    public void SetBindingContext(SolutionViewModel SolutionViewModel) {
        SolutionTree.DataContext = SolutionViewModel;
    }

这是一个延迟加载模型,因此当项目展开时,子项将被加载。

问题是我甚至没有将解决方案名称作为顶级节点。

更新
我确认模型已分配SolutionName
enter image description here

另外,根据@elgonzo的评论,我编辑.Xaml以反映对ItemsSource绑定的更改:

<TreeView Name="SolutionTree" ItemsSource="{Binding}">
    <TreeView.ItemContainerStyle>

更新2
在从TreeView中选择文件后引发事件处理程序时,将执行分配OpenFileDialog数据上下文的代码:

private void OnOpenFile(string FilePath) {
    mSolutionManager = SolutionManager.Load(FilePath);
    mSolutionViewModel = new SolutionViewModel(mSolutionManager.Solution);
    mMainWindow.SolutionExplorer.SetBindingContext(mSolutionViewModel);
    mSolutionViewModel.Refresh();

}  

当我进入Refresh()方法时:

public void Refresh() {
    OnPropertyChanged("SolutionName");
}

...我发现PropertyChangedEventHandler没有订阅者。

1 个答案:

答案 0 :(得分:2)

您对ItemsSource的绑定错误:

<TreeView Name="SolutionTree" ItemsSource="{Binding SolutionViewModel}">

ItemSource必须是IEnumerable