【问题标题】:WPF Treeview and ListBox synchronizationWPF Treeview 和 ListBox 同步
【发布时间】:2009-10-13 10:33:12
【问题描述】:

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

提前致谢 卢卡斯·格拉兹

【问题讨论】:

    标签: wpf mvvm treeview listbox viewmodel


    【解决方案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 的性能不佳

    【讨论】:

    • 感谢您提供的非常详细且易于理解的示例 :)
    猜你喜欢
    • 1970-01-01
    • 2014-10-09
    • 1970-01-01
    • 2014-10-04
    • 1970-01-01
    • 1970-01-01
    • 2012-11-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多