none
wpf mvvm模式下 递归生成的树形数据绑定到TreeView上,但TreeView不显示任何数据,如何解决此问题? RRS feed

  • 问题

  • 先看代码,分为三段,数据类型,xaml代码,ViewModel类

    树形结构类

    public class DirectoryTree
    {
        readonly List<Directory> _children = new List<Directory>();
        public IList<Directory> SubDirectories
        {
            get { return _children; }
        }
    
        public string DirectoryAddress { get; set; }
    
        public string DirectoryName { get; set; }
    }

    xaml代码

     <Button x:Name="button3" Content="获取树数据" HorizontalAlignment="Left" Margin="497,36,0,0" VerticalAlignment="Top" Width="105" Height="38" Command="{Binding addTree}" />

    <TreeView ItemsSource="{Binding TreeAddress}"> <TreeView.ItemTemplate> <HierarchicalDataTemplate ItemsSource="{Binding SubDirectories}"> <TextBlock Text="{Binding DirectoryName }" /> </HierarchicalDataTemplate> </TreeView.ItemTemplate> </TreeView>

    ViewModel类

    public class MainViewModel : INotifyPropertyChanged { private List<DirectoryTree> treeAddress; public List<DirectoryTree> TreeAddress { get { return treeAddress; } set { treeAddress = value; this.RaisePropertyChanged("TreeAddress"); } } private void RaisePropertyChanged(string name) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(name)); } } public event PropertyChangedEventHandler PropertyChanged;

    //添加树

    public void makeTree(object parameter)

            {   TreeAddress = new List<DirectoryTree>();
                string a = @"D:\androidWorkSpace";
                foreach (string directorys in Directory.GetDirectories(a))
                {
                    DirectoryTree directoryTree = new DirectoryTree();
                    directoryTree.DirectoryAddress = directorys;
                    directoryTree.DirectoryName = Path.GetDirectoryName(directorys);
                    TreeAddress.Add(directoryTree);

                }

                foreach (DirectoryTree tree12 in TreeAddress)
                { makeTrees(tree12);  }
            }
            //递归生成树
            public void makeTrees(DirectoryTree tree12)
            {
                foreach (string directorys in Directory.GetDirectories(tree12.DirectoryAddress))
                {
                    DirectoryTree directoryTree = new DirectoryTree();
                    directoryTree.DirectoryAddress = directorys;
                    directoryTree.DirectoryName = Path.GetDirectoryName(directorys);
                    tree12.SubDirectories.Add(directoryTree);
                }
                foreach (DirectoryTree tree13 in tree12.SubDirectories)
                {  makeTrees(tree13); }
            }

    public DelegateCommand addTree { get; set; }

      public MainViewModel ()
            {
                this.addTree = new DelegateCommand();
                this.addTree.ExecuteAction = new Action<object>(this.makeTree);
              }

    }

    问题描述如下:

    当Button的Click事件响应后,通过Command命令调用makeTree方法,makeTree调用makeTrees方法将treeView绑定的数据集合进行递归树生成,然而treeView容器内一个TreeViewItem都没有。

    这是怎么回事?绑定不成功?还是递归生成的树本身就不正确,?归生成本身就有问题导?

      









    2016年10月9日 13:22

答案

  • Hi 轮回的齿轮,

    你可以尝试下面MVVM实现TreeView绑定的代码(使用递归来便利目录显示节点)。

    XAML:

      <Window.Resources>
            <HierarchicalDataTemplate x:Key="MyTreeItemTemplate"  DataType="{x:Type local:MyTree}" ItemsSource="{Binding Path=Children,Mode=OneWay}">
                <StackPanel x:Name="My_SP"  Orientation="Horizontal" Margin="2">
                    <CheckBox  IsChecked="{Binding Path=IsChecked}" >
                    </CheckBox>
                    <ContentPresenter  Content="{Binding Path=Name,Mode=OneTime}" Margin="2,0"/>
                </StackPanel>
            </HierarchicalDataTemplate>
            <Style x:Key="TreeViewItemStyle" TargetType="{x:Type TreeViewItem}">
                <Setter Property="IsExpanded" Value="True" />
                <Setter Property="IsSelected" Value="{Binding Path=IsSelected,Mode=TwoWay}"/>
            </Style>
        </Window.Resources>
        <Grid>
            <DockPanel>
    
                <TreeView  x:Name="tv" ItemsSource="{Binding MyTrees}"
                          ItemContainerStyle="{StaticResource TreeViewItemStyle}"
                          ItemTemplate="{StaticResource MyTreeItemTemplate}"
                          ></TreeView>
            </DockPanel>
    
        </Grid>

    XAML.CS:

     /// <summary>
        /// Interaction logic for TreeviewBing.xaml
        /// </summary>
        public partial class TreeviewBing : Window
        {
            public TreeviewBing()
            {
                InitializeComponent();
                this.DataContext = new TreeViewModel();
            }
        }
    
        public class NotifyPropertyBase : INotifyPropertyChanged
        {
            #region INotifyPropertyChanged
            public void OnPropertyChanged(string propertyName)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
            }
            public event PropertyChangedEventHandler PropertyChanged;
            #endregion
        }
    
        public static class NotifyPropertyBaseEx
        {
            public static void SetProperty<T, U>(this T tvm, Expression<Func<T, U>> expre) where T : NotifyPropertyBase, new()
            {
                string _pro = CommonFun.GetPropertyName(expre);
                tvm.OnPropertyChanged(_pro);
            }
        }
    
        public class CommonFun
        {
            /// <summary>
            /// 返回属性名
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <typeparam name="U"></typeparam>
            /// <param name="expr"></param>
            /// <returns></returns>
            public static string GetPropertyName<T, U>(Expression<Func<T, U>> expr)
            {
                string _propertyName = "";
                if (expr.Body is MemberExpression)
                {
                    _propertyName = (expr.Body as MemberExpression).Member.Name;
                }
                else if (expr.Body is UnaryExpression)
                {
                    _propertyName = ((expr.Body as UnaryExpression).Operand as MemberExpression).Member.Name;
                }
                return _propertyName;
            }
        }
    
        public class MyTree : NotifyPropertyBase
        {
            #region 父
            public MyTree Parent
            {
                get;
                set;
            }
            #endregion
    
            #region 子
            public List<MyTree> Children
            {
              get;
               set;
            }
            #endregion
    
            #region 节点的名字
            public string Name
            {
                get;
               set;
            }
            #endregion
    
            #region Constructors
            public MyTree(string name)
            {
                this.Name = name;
                this.Children = new List<MyTree>();
    
            }
            public MyTree() { }
            public
    
            #endregion
    
            #region CheckBox是否选中
            bool? _isChecked;
            public bool? IsChecked
            {
                get
                {
                    return _isChecked;
                }
                set
                {
                    SetIsChecked(value, true, true);
                }
            }
    
            private void SetIsChecked(bool? value, bool checkedChildren, bool checkedParent)
            {
                if (_isChecked == value) return;
                _isChecked = value;
                //选中和取消子类
                if (checkedChildren && value.HasValue && Children != null)
                    Children.ForEach(ch => ch.SetIsChecked(value, true, false));
                //选中和取消父类
                if (checkedParent && this.Parent != null)
                    this.Parent.CheckParentCheckState();
                //通知更改
               this.SetProperty(x => x.IsChecked);
            }
    
            /// <summary>
            /// 检查父类是否选 中
            /// 如果父类的子类中有一个和第一个子类的状态不一样父类ischecked为null
            /// </summary>
            private void CheckParentCheckState()
            {
                bool? _currentState = this.IsChecked;
                bool? _firstState = null;
                for (int i = 0; i < this.Children.Count(); i++)
                {
                    bool? childrenState = this.Children[i].IsChecked;
                    if (i == 0)
    
                    {
                       _firstState = childrenState;
                    }
                    else if (_firstState != childrenState)
                    {
                        _firstState = null;
                    }
                }
                if (_firstState != null) _currentState = _firstState;
                SetIsChecked(_firstState, false, true);
            }
    
            #endregion
    
            #region 选中的行 IsSelected
            bool _isSelected;
            public bool IsSelected
            {
                get
                {
                    return _isSelected;
                }
                set
                {
                    _isSelected = value;
                    this.SetProperty(x => x.IsChecked);
                    if (_isSelected)
                    {
                        SelectedTreeItem = this;
                        MessageBox.Show("选中的是" + SelectedTreeItem.Name);
                    }
                    else
                        SelectedTreeItem = null;
                }
            }
           #endregion
    
            #region 选中的数据
    
            public MyTree SelectedTreeItem
           {
                get;
                set;
            }
            #endregion
    
            #region 创建树
            public void CreateTreeWithChildre(MyTree children, bool? isChecked)
            {
                this.Children.Add(children);
                children.Parent = this;
                children.IsChecked = isChecked;
            }
            #endregion
        }
    
    
      public class TreeViewModel : NotifyPropertyBase
        {
            public List<MyTree> MyTrees
            {
                get;
                set;
            }
    
            public TreeViewModel()
            {
               MyTrees = new List<MyTree>();
               MyTrees.Add(makeTree());
            }
    
            //添加树
            public MyTree makeTree()
            {
                MyTree _myT = new MyTree("androidWorkSpace");
    
                string a = @"D:\androidWorkSpace";
                foreach (string directorys in Directory.GetDirectories(a))
                {
                    MyTree _myB = new MyTree(directorys);
                    _myT.CreateTreeWithChildre(_myB, false);
                    makeTrees(directorys, _myB);
                }
                return _myT;
            }
            //递归生成树
            public void makeTrees(string directorys, MyTree mytree)
            {
                foreach (string directoryss in Directory.GetDirectories(directorys))
                {
                    MyTree _HD = new MyTree(directoryss);
                    mytree.CreateTreeWithChildre(_HD, false);
                    makeTrees(directoryss, _HD);
                }
            }
        }
    
    

    Best Regards,

    Yohann Lu

    2016年10月11日 6:35
    版主