2009-10-13 8 views
0

J'ai une vue arborescente qui montre une hiérarchie d'éléments où chaque élément a une case à cocher. Je voudrais montrer ci-dessous l'arborescence d'une liste avec tous les éléments cochés. Comment réaliser une telle fonctionnalité en utilisant le modèle MVVM?Synchronisation WPF Treeview et ListBox

Merci à l'avance Lukasz Glaz

Répondre

1

Voici un exemple:

ViewModel

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> 

code-behind

 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")))); 

Notez qu'il est une mise en œuvre assez naïve, il pourrait facilement être améliorée ... Par exemple, la liste complète des nœuds vérifiés est chaque fois réévaluées un nœud est cochée/décochée, ce qui pourrait conduire à de mauvaises performances pour un grand TreeView

+0

Merci pour votre exemple très détaillé et facile à comprendre :) – GUZ