C# TreeView定位节点
1、添加三个控件:RichTextBox,Button,TreeView
思路:
1.查询输入的条件在数据库里有没有,如果没有提示没有
2.如果有,把此结果保存下来
3.取出结果里的第一条记录,并定位(更改查找到的节点的字体颜色为红色),再把结果中已经查询到的记录删除(避免重复查询到同一个结果)
4.如果用户没有更改搜索条件,直接点击搜索,则跳到第3步,直到搜索完毕
5.如果用户更改搜索条件,则跳到第2步
2、部分代码如下:
#region 内部字段,查询用
/// <summary>
/// 保存查询到的节点的Color信息,用于还原
/// </summary>
private Color _queryColor { get; set; }
/// <summary>
/// 保存查询的数据
/// </summary>
private DataTable _dtQueryNode { get; set; }
/// <summary>
/// 保存查询的条件
/// </summary>
private string _queryString { get; set; }
/// <summary>
/// 查询状态 true:查询条件改变,false查询条件没变
/// </summary>
private bool _queryStatu { get; set; }
#endregion

3、/// <summary>
/// 首次加载,全部加载
/// </summary>
private void loadType()
{
//实例化一个TreeNode,名字是app.config文件里设置的
//ConfigurationManager,这个类需要添加引用System.Configuration
TreeNode treeNode = new TreeNode(ConfigurationManager.AppSettings["treeNodeTitle"]);
//设置tag为-1方便识别是否是根节点
treeNode.Tag = "-1";
//设置Name为0,方便识别数据库里的父节点
treeNode.Name = "0";
//加载全部
loadType(0, treeNode);
//清空控件节点数据,避免数据重复添加
treeView_Type.Nodes.Clear();
//添加控件节点数据
treeView_Type.Nodes.Add(treeNode);
}

4、/// <summary>
/// 加载类型名称,递归全部加载
/// </summary>
/// <param name="_typeParentID">父节点</param>
/// <param name="treeNode">TreeNode</param>
/// <returns></returns>
private void loadType(int _typeParentID,TreeNode treeNode)
{
this.Text = ConfigurationManager.AppSettings["appName"];
// treeNode.Nodes.Clear();
DataTable dt = PictureDbOperator.GetDataSet(
string.Format("select type_id,type_name from type where type_parent_id={0} order by type_name",
_typeParentID));
if (dt.Rows.Count>0)
{//检查是否有类型数据
TreeNode tn = null;
//读取数据,并写入treeview
foreach (DataRow item in dt.Rows)
{
tn = new TreeNode(item["type_name"].ToString());
tn.Name = item["type_id"].ToString();
//节点下有图片,这个用于判断是否是图片
tn.Tag = "T";
loadType(int.Parse(item["type_id"].ToString()), tn);
treeNode.Nodes.Add(tn);
}
}
}

5、/// <summary>
/// 查询类型,根据类型名称
/// </summary>
/// <param name="typeName">类型名称</param>
private void loadType(string typeName)
{
//直接在treeview里查询
if (typeName == "")
{//条件为空时,调出所有的类型
loadType();
return;
}
this.Text = ConfigurationManager.AppSettings["appName"];
try
{
if (_queryStatu)
{//条件变化时
//先从数据库里查询到相关类型
string strSQL = string.Format("select * from type where type_name like '%{0}%' order by type_name,type_id asc", typeName);
//保存查询出来的数据
_dtQueryNode = PictureDbOperator.GetDataSet(strSQL);
//保存查询条件,用于判断是否更改了查询条件
_queryString = typeName;
}
//判断是否查询到数据
if (_dtQueryNode != null && _dtQueryNode.Rows.Count > 0)
{//如果查询得到有数据
#region
//取出第一条查询到的数据
DataRow dr = _dtQueryNode.Rows[0];
//调用方法查找到相应的treenode
TreeNode tn = FindTreeNode(dr["type_name"].ToString(), treeView_Type.Nodes[0]);
//保存treenode原始字体颜色,因为下面把找到的treenode更改了颜色
_queryColor = tn.ForeColor;
//更改查找到的treenode的颜色为红色
tn.ForeColor = Color.Red;
//设置控件选中的节点为查找到的节点
treeView_Type.SelectedNode = tn;
//展开节点,这个暂时不知道是怎么会事,会把所有的节点都展开了
treeView_Type.SelectedNode.Parent.ExpandAll();
//移除已经查找到的条件
_dtQueryNode.Rows.Remove(dr);
#endregion
}
else
{
MessageBox.Show(string.Format("{0}{1}",
ConfigurationManager.AppSettings["searchTypeErrorMessage"], typeName));
}
}
catch (Exception ex) { MessageBox.Show("查询出错:" + ex.Message); }
}

6、 /// <summary>
/// 按钮Click事件搜索类型,并重新显示到树结构里
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_Search_Click(object sender, EventArgs e)
{
//还原被改变为node
if (_queryColor != null && treeView_Type.SelectedNode != null)
{
treeView_Type.SelectedNode.ForeColor = _queryColor;
}
//如果查询条件不为空且查询条件不变时,更改状态为false,表示没有更改条件
_queryStatu = (_queryString != "" && _queryString == richTextBox_Search.Text.Trim()) ? false : true;
loadType(richTextBox_Search.Text.Trim());
}

7、 /// <summary>
/// 递归查询节点,来源网络
/// </summary>
/// <param name="typeName">要查询的节点内容</param>
/// <param name="tnParent">TreeNode</param>
/// <returns></returns>
private TreeNode FindTreeNode(string typeName, TreeNode tnParent)
{
if (tnParent == null)
return null;
//这里也可以用tnParent.Text==typeName
//因为在调用它的方法那里,
//已经是查询到的节点的完整内容
if (tnParent.Text.IndexOf(typeName) != -1)
return tnParent;
TreeNode tnRet = null;
//循环tnParent的子节点
foreach (TreeNode tn in tnParent.Nodes)
{//调用自己
tnRet = FindTreeNode(typeName, tn);
//如果找到就跳出循环
if (tnRet != null)
break;
}
return tnRet;
}

8、数据库表Type
CREATE TABLE [dbo].[Type] (
[type_id] INT IDENTITY (1, 1) NOT NULL,
[type_name] NVARCHAR (500) NULL,
[type_mem] NVARCHAR (50) NULL,
[type_parent_id] INT NOT NULL
);

9、测试数据
SET IDENTITY_INSERT [dbo].[Type] ON
INSERT INTO [dbo].[Type] ([type_id], [type_name], [type_mem], [type_parent_id]) VALUES (1, N'中国工商银行', N'中国工商银行', 0)
INSERT INTO [dbo].[Type] ([type_id], [type_name], [type_mem], [type_parent_id]) VALUES (3, N'中国建设银行', N'中国建设银行', 0)
INSERT INTO [dbo].[Type] ([type_id], [type_name], [type_mem], [type_parent_id]) VALUES (6, N'中国民生银行', NULL, 0)
INSERT INTO [dbo].[Type] ([type_id], [type_name], [type_mem], [type_parent_id]) VALUES (7, N'交通银行', NULL, 0)
INSERT INTO [dbo].[Type] ([type_id], [type_name], [type_mem], [type_parent_id]) VALUES (11, N'交通银行青羊支行', N'交通银行', 7)
INSERT INTO [dbo].[Type] ([type_id], [type_name], [type_mem], [type_parent_id]) VALUES (12, N'中国工商银行成华支付', N'中国工商银行', 1)
INSERT INTO [dbo].[Type] ([type_id], [type_name], [type_mem], [type_parent_id]) VALUES (13, N'交通银行成都支行', NULL, 7)
INSERT INTO [dbo].[Type] ([type_id], [type_name], [type_mem], [type_parent_id]) VALUES (14, N'中国农业银行', NULL, 0)
INSERT INTO [dbo].[Type] ([type_id], [type_name], [type_mem], [type_parent_id]) VALUES (15, N'中国农商银行', NULL, 0)
INSERT INTO [dbo].[Type] ([type_id], [type_name], [type_mem], [type_parent_id]) VALUES (17, N'德阳银行', NULL, 0)
INSERT INTO [dbo].[Type] ([type_id], [type_name], [type_mem], [type_parent_id]) VALUES (18, N'德阳银行成都支行', NULL, 17)
INSERT INTO [dbo].[Type] ([type_id], [type_name], [type_mem], [type_parent_id]) VALUES (19, N'中国建设银行人民支行', NULL, 3)
INSERT INTO [dbo].[Type] ([type_id], [type_name], [type_mem], [type_parent_id]) VALUES (20, N'中国工商银行青羊支行', NULL, 1)
INSERT INTO [dbo].[Type] ([type_id], [type_name], [type_mem], [type_parent_id]) VALUES (21, N'中国建设银行成都支行', NULL, 3)
SET IDENTITY_INSERT [dbo].[Type] OFF
