【问题标题】:How to bind TreeView to ViewModel?如何将 TreeView 绑定到 ViewModel?
【发布时间】:2014-08-06 20:53:46
【问题描述】:

我有一个视图模型如下:

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

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

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

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

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 没有订阅者。

【问题讨论】:

  • 您需要为您的 SolutionViewModel 类实现 INotifyPropertyChanged 接口,并在 SolutionName时触发 PropertyChanged 事件> 属性变化。我猜 TreeViewItemViewModel 也缺少 INotifyPropertyChanged 实现。此外,您的 TreeView 似乎缺少 TreeViewItemViewModel... 的 DataTemplate
  • TreeViewItemViewModel 是一个抽象类,为INotifyPropertyChanged 提供实现。当SolutionViewModel 被分配为树视图数据上下文时,SoltuionName 已被分配并且此后不会更改。我更新了问题以反映继承自 TreeViewItemViewModel 的继承链。
  • 好的。只是解决方案名称没有显示。属性 SolutionViewModel(在 ItemsSource 绑定中使用)未正确设置(或未触发 PropertyChanged 事件以防在属性接收其预期值之前建立绑定),或 SolutionName(因此 mSolution.Name)在建立数据绑定时为空。如果在数据绑定建立后设置了 SolutionName(即 mSolution.Name),除非您通过 PropertyChanged 事件通知它,否则绑定无法知道这一点。
  • 如果您设置SolutionTree.DataContext = SolutionViewModel;,那么数据绑定ItemsSource="{Binding SolutionViewModel}" 将尝试绑定到属性DataContext.SolutionViewModel,这将等于SolutionViewModel.SolutionViewModel。我想你应该尝试ItemsSource="{Binding}" 绑定到 SolutionViewModel(即 DataContext)。
  • 我看到你在一小时前进行了编辑。看起来你没有注意到我最后的评论,关于尝试将 TreeView.ItemSource 设置为ItemsSource="{Binding}"(有关详细信息,请参阅我之前的评论)。

标签: c# xaml data-binding treeview viewmodel


【解决方案1】:

您对ItemsSource 的绑定是错误的:

&lt;TreeView Name="SolutionTree" ItemsSource="{Binding SolutionViewModel}"&gt;

ItemSource 必须是 IEnumerable

【讨论】:

  • ...或DataContext = new List&lt;SolutionViewModel&gt;() {SolutionViewModel }; ;) 我这样做了,它有效。
猜你喜欢
  • 2011-02-28
  • 2012-07-03
  • 2011-11-30
  • 2016-11-17
  • 2015-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-19
相关资源
最近更新 更多