DevExpress控件XtraTreeList的使用心得

数据展示

数据源绑定
需要设置KeyFieldName和ParentFieldName后绑定数据
treeList1.DataSource = dataTable1;
且KeyFieldName列不能存在重复的数据

手动增加节点
var node = treeList1.AppendNode("", null);


注:该方法有多个重载,可灵活设置节点的父节点,图标,勾选状态,tag等
设置node上的数据
node.SetValue(treeListColumn1, obj1);
node.Tag = obj2;



外观

自定义设置节点的图标(需要绑定一个imageCollection给TreeList的SelectImageList)
private void treeListMaster_CustomDrawNodeImages(object sender, DevExpress.XtraTreeList.CustomDrawNodeImagesEventArgs e)
{
	var index = e.Node.GetValue("IMAGEINDEX");


	if (index.ToString() != string.Empty)
	{
		e.SelectImageIndex = Convert.ToInt32(index);
	}
}


其他外观设置基本都在OptionsView下面,可以设置:
是否显示行头,列头,水平线,垂直线,勾选框等。


OptionsFind下可以设置搜索栏的显示方式,是否显示搜索,清空按钮等。但是这个自带的搜索比较鸡肋,当一个节点满足条件,但是其父节点不满足条件时这个节点也无法显示。
除非事先调用treeList1.ExpandAll();将节点全部展开显示,当数据比较大的时候也是比较麻烦的,后面会介绍一种自定义的方法。

拖曳操作

如果需要从外面拖入数据,需要设置
treeList1.AllowDrop = true;
如果需要内部拖曳节点,需要设置
treeList1.OptionsBehavior.DragNodes = true;
相关的几个事件:
DragEnter——当拖曳进入到treeList中时
DragOver——相当于在treeList上的MouseMove
DragDrop——拖曳结束松开鼠标时
DragLeave——拖曳节点出treeList时
从外部控件(比如GridControl)拖曳数据到树上,流程:
//1
Grid的MouseMove事件判断是否左键按下,执行treeList1.DoDragDrop(yourData, DragDropEffects.Copy);
//2
treeList的DragEnter事件,执行e.Effect = DragDropEffects.Copy;//可以执行判断,如果不满足可赋值DragDropEffects.None禁止拖曳操作
//3
treeList的DragDrop事件,获取数据e.Data.GetData(typeof(YourType)) as YourType,并判断当前节点:
var hi = treeListMaster.CalcHitInfo(treeListMaster.PointToClient(new Point(e.X, e.Y)));
var targetNode = hi.Node;
此处可通过hi.HitInfoType判断当前拖放的位置,是Cell,Column,Row,StateImage,Button,FilterPanel,ScrollBar,CheckBox....
然后执行treeList1.AppendNode(...);即可。


将树节点拖出控件执行删除操作,想当然地在DragLeave中操作,问题来了:
1.操作后,treeList依然认为在执行Drag操作,除非找到一个时机将DragDropEffects置为None;
2.体验不好,鼠标刚刚离开树,还没抬起左键,提示的MessageBox就弹出来了,不是想要的效果;
多次实验后还是换为另一种思路(这其实是DevExpress的Demo):
在treeList外部放置一个label,图标设置为垃圾桶:        
private void labelControl1_DragEnter(object sender, DragEventArgs e)
{
	e.Effect = DragDropEffects.Copy;
	labelControl1.Appearance.ImageIndex = 1;//换为打开的垃圾桶
}


private void labelControl1_DragDrop(object sender, DragEventArgs e)
{
	//这里执行删除节点操作
	DeleteNode();
	labelControl1.Appearance.ImageIndex = 0;//换为关闭的垃圾桶
}


private void labelControl1_DragLeave(object sender, EventArgs e)
{
	labelControl1.Appearance.ImageIndex = 0;//换位关闭的垃圾桶
}


树内部拖曳,移动或节点排序也可以在DragDrop中操作

treeList1.SetNodeIndex(dragnode, treeList1.GetNodeIndex(targetnode));

然后保存这个顺序即可。
问题来了:如何判断是移动节点还是排序?在拖曳的时候树控件虽然会提示箭头(向上/下表示移动,向右表示加为子节点),但是在DragDrop的代码中却无法判断这个状态。
无奈只好改为其他的事件来处理移动节点和节点排序:
AfterDragNode——拖曳节点结束后触发
通过比对dragNode的拖曳前后的父节点,判断是排序还是移动节点。


其他的还有DragObjectDrop,这个名字比较坑,其实只在拖曳treeListColumn时触发。

节点搜索过滤

前面提到treeList提供了OptionsFind,可以展示一个Find框,可以将任何匹配的文字高亮,如果打开了FilterNode选项还可以实现节点过滤。但是存在一个问题:
如果某节点匹配条件,但其父节点不匹配,该节点仍被过滤掉。除非在Find之前将树全部展开treeList1.ExpandAll();明显我们不希望这样。
根据DevExpress的官方答复,他们会在后续版本中提供一个新的OptionsFilter.FilterMode:Extended,但是目前的版本还没有。
实现方法,放置一个ButtonEdit在树控件的上方,并实现一个FilterNodeOperation类:

class FilterNodeOperation : TreeListOperation
{
	string pattern;


	public FilterNodeOperation(string _pattern)
	{
		pattern = _pattern;
	}


	public override void Execute(TreeListNode node)
	{
		if (NodeContainsPattern(node, pattern))
		{
			node.Visible = true;
			
			//if (node.ParentNode != null)
			//    node.ParentNode.Visible = true;
			
			//必须要递归查找其父节点全部设置为可见
			var pNode = node.ParentNode;
			while (pNode != null)
			{
				pNode.Visible = true;
				pNode = pNode.ParentNode;
			}
		}
		else
			node.Visible = false;
	}


	bool NodeContainsPattern(TreeListNode node, string pattern)
	{
		foreach (TreeListColumn col in node.TreeList.VisibleColumns)
		{
			if (node.GetDisplayText(col).Contains(pattern))
				return true;
		}
		return false;
	}
}
//在ButtonEdit的ButtonClick事件中执行这个Operation:
private void buttonEdit1_ButtonClick(object sender, DevExpress.XtraEditors.Controls.ButtonPressedEventArgs e)
{
	var operation = new FilterNodeOperation(buttonEdit1.EditValue != null ? buttonEdit1.EditValue.ToString() : "");
	treeListMaster.NodesIterator.DoOperation(operation);
}



你可能感兴趣的:(C#/.NET)