65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.19/5 (14投票s)

2016年2月9日

CPOL

2分钟阅读

viewsIcon

75323

downloadIcon

4773

本文将指导您“如何从数据库填充并添加最多 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 项目
  • 将树视图拖放到窗体上
  • 向窗体添加上下文菜单。 此上下文菜单将用于执行以下功能
    1. 查看特定节点的详细数据
    2. 在当前级别添加节点
    3. 在选定节点下添加新节点
  • 双击窗体,创建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。 我们可以自动在任何级别生成代码。

© . All rights reserved.