使用自动代码生成,从数据库将 TreeView 填充到 N 级,以及在运行时生成新项目






4.19/5 (14投票s)
本文将指导您“如何从数据库填充并添加最多 N 级的 TreeView 节点”。 您将能够在任何级别添加新节点,并将其扩展到 N 级,并为任何子节点自动生成代码。
引言
TreeView
控件用于使用可展开的节点表示分层数据。 TreeView
控件也适用于 WinForms 和 WPF。
本文将指导您“如何从数据库填充并添加最多 N 级的 TreeView 节点”。 您将能够在任何级别添加新节点,并将其扩展到 N 级,并为任何子节点自动生成代码。
数据库结构
首先,使用给定的模型创建一个数据库表。 我们将仅使用一个表,因为我们需要将其扩展到 N 级。 我使用了 SQL Server 2014。 可以使用任何版本的 SQL Server。
CREATE TABLE [dbo].accounts(
[code] [int] NOT NULL,
[ac_name] [nvarchar](50) NOT NULL,
[parent] [int] NOT NULL,
[type] [nvarchar](20) NOT NULL,
[levelno] [int] NOT NULL,
[fixed] [nvarchar](50) NULL,
[direct] [nvarchar](50) NULL,
[open_bal] [decimal](18, 2) NULL,
[dt] [datetime] NULL CONSTRAINT [DF_chart_dt] DEFAULT (getdate()),
[active] [int] NOT NULL CONSTRAINT [DF_chart_active] DEFAULT ((1)),
[cntr] [int] IDENTITY(1,1) NOT NULL,
CONSTRAINT [PK_chart] PRIMARY KEY CLUSTERED
(
[code] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, _
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
字段‘code
’将是主键。 它将用于标识每个帐户。 程序将自动为任何新节点生成代码。
向此表添加一些虚拟数据
SET IDENTITY_INSERT [dbo].accounts ON
GO
INSERT [dbo].accounts ([code], [ac_name], [parent], [type], [levelno], [fixed], _
[direct], [open_bal], [dt], [active], [cntr]) VALUES (1, N'Assets', 0, _
N'Parent Account', 0, N'NA', N'NA', CAST(0.00 AS Decimal(18, 2)), _
CAST(N'2015-02-23 21:09:27.327' AS DateTime), 1, 1)
GO
INSERT [dbo].accounts ([code], [ac_name], [parent], [type], [levelno], [fixed], _
[direct], [open_bal], [dt], [active], [cntr]) VALUES (2, N'Liabilities', 0, _
N'Parent Account', 0, N'NA', N'NA', CAST(0.00 AS Decimal(18, 2)), _
CAST(N'2015-02-23 21:09:27.327' AS DateTime), 1, 2)
GO
INSERT [dbo].accounts ([code], [ac_name], [parent], [type], [levelno], [fixed], [direct], _
[open_bal], [dt], [active], [cntr]) VALUES (3, N'Equity', 0, N'Parent Account', 0, _
N'NA', N'NA', CAST(0.00 AS Decimal(18, 2)), _
CAST(N'2015-02-23 21:09:27.327' AS DateTime), 1, 3)
GO
INSERT [dbo].accounts ([code], [ac_name], [parent], [type], [levelno], [fixed], [direct], _
[open_bal], [dt], [active], [cntr]) VALUES (4, N'Revenue', 0, N'Parent Account', _
0, N'Variable', N'Indirect', CAST(0.00 AS Decimal(18, 2)), _
CAST(N'2015-02-26 00:00:00.000' AS DateTime), 1, 38)
GO
INSERT [dbo].accounts ([code], [ac_name], [parent], [type], [levelno], [fixed], [direct], _
[open_bal], [dt], [active], [cntr]) VALUES (101, N'Current Assets', 1, _
N'Parent Account', 1, N'NA', N'NA', CAST(0.00 AS Decimal(18, 2)), _
CAST(N'2015-02-23 21:09:27.327' AS DateTime), 1, 4)
GO
INSERT [dbo].accounts ([code], [ac_name], [parent], [type], [levelno], [fixed], [direct], _
[open_bal], [dt], [active], [cntr]) VALUES (102, N'Fixed Assets', 1, N'Parent Account', _
1, N'NA', N'NA', CAST(0.00 AS Decimal(18, 2)), _
CAST(N'2015-02-23 21:09:27.327' AS DateTime), 1, 5)
GO
INSERT [dbo].accounts ([code], [ac_name], [parent], [type], [levelno], [fixed], [direct], _
[open_bal], [dt], [active], [cntr]) VALUES (201, N'Short Term Liabilities', 2, _
N'Parent Account', 1, N'NA', N'NA', CAST(0.00 AS Decimal(18, 2)), _
CAST(N'2015-02-23 21:09:27.327' AS DateTime), 1, 6)
GO
INSERT [dbo].accounts ([code], [ac_name], [parent], [type], [levelno], [fixed], [direct], _
[open_bal], [dt], [active], [cntr]) VALUES (202, N'Long Term Liabilities', 2, _
N'Parent Account', 1, N'NA', N'NA', CAST(0.00 AS Decimal(18, 2)), _
CAST(N'2015-02-23 21:09:27.327' AS DateTime), 1, 7)
GO
SET IDENTITY_INSERT [dbo].accounts OFF
GO
填充 TreeView
创建表并向其中添加数据后,现在我们可以将数据填充到TreeView
中。
请按照以下步骤操作
- 在 Visual Studio 中创建一个 WinForm 项目
- 将树视图拖放到窗体上
- 向窗体添加上下文菜单。 此上下文菜单将用于执行以下功能
- 查看特定节点的详细数据
- 在当前级别添加节点
- 在选定节点下添加新节点
- 双击窗体,创建
Form_Load
事件。 我们将在窗体加载时填充树。 - 在窗体加载时,我们将从 SQL Server 获取数据并将其保存到数据表。
- 以下函数将把数据填充到
TreeView
中。 PopulateTreeView
是一个递归函数。 它会调用自身,直到TreeView
中没有更多的节点可以显示为止。
private void PopulateTreeView(int parentId, TreeNode parentNode)
{
TreeNode childNode;
foreach (DataRow dr in _acountsTb.Select("[parent]=" + parentId))
{
TreeNode t = new TreeNode();
t.Text = dr["code"].ToString() + " - " + dr["ac_name"].ToString();
t.Name = dr["code"].ToString();
t.Tag = _acountsTb.Rows.IndexOf(dr);
if (parentNode == null)
{
treeView1.Nodes.Add(t);
childNode = t;
}
else
{
parentNode.Nodes.Add(t);
childNode = t;
}
PopulateTreeView(Convert.ToInt32(dr["code"].ToString()), childNode);
}
}
显示节点数据
以下函数用于显示特定节点的详细信息。
private void ShowNodeData(TreeNode nod) {
DataRow r = _acountsTb.Rows[int.Parse(nod.Tag.ToString())];
txtCode.Text = r["code"].ToString();
txtName.Text = r["ac_name"].ToString();
dtpDate.Value = DateTime.Parse(r["dt"].ToString());
textBox1.Text = r["open_bal"].ToString();
if (r["type"].ToString().Equals("Parent Account"))
{
radioParent.Checked = true;
textBox1.Enabled = false;
}
else
radioTransaction.Checked = true;
if (r["fixed"].ToString().Equals("NA"))
radioNA1.Checked = true;
else if (r["fixed"].ToString().Equals("Fixed"))
radioFixed.Checked = true;
else
radioVariable.Checked = true;
if (r["direct"].ToString().Equals("NA"))
radioNA2.Checked = true;
else if (r["direct"].ToString().Equals("Direct"))
radioDirect.Checked = true;
else
radioIndirect.Checked = true;
txtName.Focus();
}
在此级别添加新节点
以下事件处理程序处理上下文菜单项“在此级别”的单击操作。 此事件首先为要插入的新项目创建代码。
private void atThisLevelToolStripMenuItem_Click(object sender, EventArgs e)
{
_selectedNode = treeView1.SelectedNode;
int max = 0;
if (treeView1.Nodes.Count > 0)
{
_parent = int.Parse(_acountsTb.Rows[int.Parse(_selectedNode.Tag.ToString())]["parent"].ToString());
DataRow[] nodes = _acountsTb.Select("[parent]=" + _parent);
foreach (DataRow r in nodes)
{
int n = int.Parse(r["code"].ToString());
if (n > max)
max = n;
}
}
max += 1;
txtCode.Text = max.ToString();
_newNode = true;
_thisLevel = true;
txtName.Focus();
}
在选定节点下添加新节点
以下事件处理程序处理上下文菜单项“在选择下”的单击操作。 此事件首先为要插入的新项目创建代码。
private void underSelectedToolStripMenuItem_Click(object sender, EventArgs e)
{
_selectedNode = treeView1.SelectedNode;
DataRow r = _acountsTb.Rows[int.Parse(treeView1.SelectedNode.Tag.ToString())];
if (r["type"].ToString().Equals("Parent Account"))
{
_newNode = true;
_thisLevel = false;
string code = string.Empty;
_parent = int.Parse(_acountsTb.Rows[int.Parse
(_selectedNode.Tag.ToString())]["code"].ToString());
if (_selectedNode.Nodes.Count > 0)
{
DataRow[] nodes = _acountsTb.Select("[parent]=" + _parent);
int max = 0;
foreach (DataRow ra in nodes)
{
int n = int.Parse(ra["code"].ToString());
if (n > max)
max = n;
}
max += 1;
txtCode.Text = max.ToString();
code = max.ToString();
}
else
{
if (_selectedNode.Level < 3)
code = "01";
else
code = "001";
txtCode.Text = r["code"] + code;
}
txtName.Focus();
}
else
{
_newNode = false;
MessageBox.Show("New Account can't be opened under a Transaction Account",
"Account opening Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
结论
上述教程展示了如何在 C# 中动态创建和填充最多 N 级的TreeView
。 我们可以自动在任何级别生成代码。