TreeListView--拿来主义到底好不好
写这篇博客的原因是:希望有在项目中遇到和我一样问题的人能够找到中文的解决方案,节省时间,仅此而已
此功能诸多代码来源于国外的网站和某些项目,地址为http://www.codeproject.com/Articles/30721/WPF-TreeListView-Control
我只是站在别人的楼顶,顶着风,尿了一把。
废话不多说,直接上效果图,一幕了然:
接下来上的就是我这个代码的整体结构了。
TreeListViewModel是CodeProject里面的人写的,为项目框架核心。
TreeListViewWpfApplication为TreeListView的主要实现,下面我主要介绍怎么实现
(TreeListViewModel里面代码能力有限,目前为止也没看出个什么东西)
先给大家介绍Model下面的Student类的代码吧
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TreeListViewWpfApplication
{
public class Student
{
public Student(string types, string name, int age, string love, List<Student> listStudent)
{
Types = types;
Name = name;
Age = age;
Love = love;
Childs = listStudent;
}
public Student() { }
public string Types { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public string Love { get; set; }
public List<Student> Childs { get; set; }
}
}
下面要说的是绑定的数据的格式。
其实要实现TreeListView效果,绑定的数据类型必须实现接口ITreeModel。
接下来就需要我们来定义一个用来存储数据方式的类了(我这样说肯定有错误),这个类的名字为TreeListModel。
那接下贴上TreeListModel的代码。
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TreeListViewModel.Tree;
using System.Collections;
namespace TreeListViewWpfApplication
{
public class SubTreeModel<T> : ITreeModel
{
List<TreeModel<T>> _trees = new List<TreeModel<T>>();
public SubTreeModel(List<TreeModel<T>> trees)
{
_trees = trees;
}
public IEnumerable GetChildren(object parent)
{
if (parent == null)
{
foreach (var item in _trees)
{
yield return item;
}
}
else
{
var parentModel = parent as TreeModel<T>;
if (parentModel != null)
{
foreach (var item in parentModel.Childs)
{
yield return item;
}
}
}
}
public bool HasChildren(object parent)
{
var parentModel = parent as TreeModel<T>;
if (parentModel != null)
return parentModel.Childs.Count > 0;
return false;
}
}
public class TreeModel<T>
{
T item;
public T Item
{
get { return item; }
set { item = value; }
}
List<TreeModel<T>> childs = new List<TreeModel<T>>();
public List<TreeModel<T>> Childs
{
get { return childs; }
set { childs = value; }
}
}
}
如果对迭代器不是很懂的,下面的这个地址可以简单的了解一下迭代器的作用。
TreeModel<T>这个数据类型和Student一一对应。
WPF前台绑定的数据类型为 SubTreeModel<T> 类型。
接下来我们看看WPF前台的代码
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tree="clr-namespace:TreeListViewModel.Tree;assembly=TreeListViewModel"
xmlns:local="clr-namespace:TreeListViewWpfApplication"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:AgeConverter x:Key="AgeConverter"/>
</Window.Resources>
<Grid>
<tree:TreeList Name="treeList">
<tree:TreeList.View>
<GridView>
<GridView.Columns>
<GridViewColumn Width="140" Header="Type">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<tree:RowExpander/>
<TextBlock Text="{Binding Item.Types}"></TextBlock>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Name" Width="100" DisplayMemberBinding="{Binding Item.Name}"/>
<GridViewColumn Header="Age" Width="100" DisplayMemberBinding="{Binding Item.Age,Converter={StaticResource AgeConverter}}"/>
<GridViewColumn Header="Love" Width="100" DisplayMemberBinding="{Binding Item.Love}"/>
</GridView.Columns>
</GridView>
</tree:TreeList.View>
</tree:TreeList>
</Grid>
</Window>
这里我就不把AgeConverter的代码帖出来了。
直接看MainWindow的后台代码吧。
MainWindow主要是给Student赋值并把数据填充到数据类型为 SubTreeModel<T>中。
即SubTreeModel<Student> ,对应SubTreeModel<T>中的List<TreeModel<T>>即List<TreeModel<Student>>
TreeModel<Student>对应的是TreeModel<T>类,而TreeModel<T>
里面包含 Item,和Childs属性,与Student类的Types字段和Childs字段刚好吻合。
下面是后台代码的实现
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace TreeListViewWpfApplication
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MainWindow_Loaded);
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
Reload();
treeList.Model = ListGasConfig;
}
private SubTreeModel<Student> _listGasConfig;
public SubTreeModel<Student> ListGasConfig
{
get { return _listGasConfig; }
set
{
_listGasConfig = value;
}
}
private void Reload()
{
var configs = new List<Student>(){
new Student ()
{
Types="A", Childs=new List<Student>()
{
new Student(){ Name="测试A1", Age=25, Love="赵某", Childs=null},
new Student(){ Name="测试A2", Age=18, Love="小护士", Childs=null},
}
},
new Student ()
{
Types="B", Childs=new List<Student>()
{
new Student(){ Name="测试B1", Age=24, Love="小琴", Childs=null},
new Student(){ Name="测试B2", Age=22, Love="。。", Childs=null},
}
},
new Student()
{
Types="The future",Childs=new List<Student>()
{
new Student(){ Name="The last one", Age=-1, Love="待定", Childs=null}
}
}
};
var treeModels = new List<TreeModel<Student>>();
foreach (Student item in configs)
{
if (item.Childs != null)
{
treeModels.Add(BuildTreeModels(item, item.Childs));
}
}
ListGasConfig = new SubTreeModel<Student>(treeModels);
}
private TreeModel<Student> BuildTreeModels(Student GasConfig, List<Student> liststudent)
{
var treeModel = new TreeModel<Student>();
treeModel.Item = new Student() { Types = GasConfig.Types, Childs = liststudent };
if (liststudent.Count > 0)
{
foreach (Student item in liststudent)
{
treeModel.Childs.Add(new TreeModel<Student>() { Item = item });
}
}
return treeModel;
}
}
}
下面是我的DEMO,有码有真相,/Files/xuliangjie/TreeListView.rar
再次申明,上述核心代码有很大一部分来自国外网站,我只是借鉴别人的核心,和我们项目中实际的运用,此篇文章不代表本人任何立场,我只是做个总结,分享一下,这个功能很实用。