2009-10-13 47 views
0

我有一个树视图表示,其中每个项目都有一个复选框的项目的层次结构。我想在树形视图下面显示一个包含所有选中项的列表框。如何使用MVVM模式实现这样的功能?WPF Treeview和列表框同步

在此先感谢 卢卡斯Glaz

回答

1

下面是一个例子:

视图模型

public class TreeNodeViewModel : ViewModelBase 
{ 
    #region Constructors 

    public TreeNodeViewModel(string text, params TreeNodeViewModel[] nodes) 
     : this(text, new ObservableCollection<TreeNodeViewModel>(nodes)) 
    { 
    } 

    public TreeNodeViewModel(string text, ObservableCollection<TreeNodeViewModel> nodes) 
    { 
     Text = text; 
     Nodes = nodes; 
     foreach (var node in Nodes) 
     { 
      node.Parent = this; 
     } 
     Nodes.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Nodes_CollectionChanged); 
    } 

    #endregion 

    #region Private methods 

    private void Nodes_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) 
    { 
     foreach (var node in e.OldItems.Cast<TreeNodeViewModel>()) 
     { 
      node.Parent = null; 
     } 
     foreach (var node in e.NewItems.Cast<TreeNodeViewModel>()) 
     { 
      node.Parent = this; 
     } 
     OnPropertyChanged("CheckedNodes"); 
    } 

    private void NotifyParent() 
    { 
     if (Parent != null) 
     { 
      Parent.OnPropertyChanged("CheckedNodes"); 
      Parent.NotifyParent(); 
     } 
    } 

    #endregion 

    #region Private data 

    private string _text; 
    private bool _isChecked; 
    private TreeNodeViewModel _parent; 

    #endregion 

    #region Public properties 

    public string Text 
    { 
     get { return _text; } 
     set 
     { 
      if (value != _text) 
      { 
       _text = value; 
       OnPropertyChanged("Text"); 
      } 
     } 
    } 

    public bool IsChecked 
    { 
     get { return _isChecked; } 
     set 
     { 
      if (value != _isChecked) 
      { 
       _isChecked = value; 
       NotifyParent(); 
       OnPropertyChanged("IsChecked"); 
      } 
     } 
    } 

    public ObservableCollection<TreeNodeViewModel> Nodes { get; private set; } 

    public IEnumerable<TreeNodeViewModel> CheckedNodes 
    { 
     get 
     { 
      foreach (var node in Nodes) 
      { 
       if (node.IsChecked) 
        yield return node; 
       foreach (var child in node.CheckedNodes) 
       { 
        yield return child; 
       } 
      } 
     } 
    } 

    public TreeNodeViewModel Parent 
    { 
     get { return _parent; } 
     private set 
     { 
      if (value != _parent) 
      { 
       _parent = value; 
       OnPropertyChanged("Parent"); 
      } 
     } 
    } 

    #endregion 
} 

XAML

<TreeView Grid.Row="0" ItemsSource="{Binding Nodes}"> 
     <TreeView.ItemTemplate> 
      <HierarchicalDataTemplate ItemsSource="{Binding Nodes}"> 
       <StackPanel Orientation="Horizontal"> 
        <CheckBox IsChecked="{Binding IsChecked}" /> 
        <TextBlock Text="{Binding Text}" /> 
       </StackPanel> 
      </HierarchicalDataTemplate> 
     </TreeView.ItemTemplate> 
    </TreeView> 
    <ListBox Grid.Row="1" ItemsSource="{Binding CheckedNodes}"> 
     <ListBox.ItemTemplate> 
      <DataTemplate> 
       <TextBlock Text="{Binding Text}" /> 
      </DataTemplate> 
     </ListBox.ItemTemplate> 
    </ListBox> 

代码隐藏

 this.DataContext = new TreeNodeViewModel(
      null, 
      new TreeNodeViewModel(
       "1", 
       new TreeNodeViewModel(
        "1.1", 
        new TreeNodeViewModel("1.1.1"), 
        new TreeNodeViewModel("1.1.2")), 
       new TreeNodeViewModel("1.2")), 
      new TreeNodeViewModel(
       "2", 
       new TreeNodeViewModel("2.1"), 
       new TreeNodeViewModel(
        "2.2", 
        new TreeNodeViewModel("2.2.1")))); 

请注意,这是一个相当幼稚的做法,很容易就会被提高...例如,检查节点的整个列表重新评估每一个节点被选中/取消的时候,这可能导致糟糕表现为一个大的TreeView

+0

谢谢您的非常详细,容易理解的例子:) – GUZ 2009-10-13 12:56:17