我要使用一个TreeView来绑定数据,涉及到了三张表,我简单描述
大表←中表←小表
这是它们之间的关系,和三级联动差不多
我用了两个foreach但是会有重复的数据被加载进去.public partial class Form1 : Form
    {
        //工作区
        DataSet ds = new DataSet();
        //管网
        DataSet ds2 = new DataSet();
        public Form1()
        {
            InitializeComponent();
        }        private void Form1_Load(object sender, EventArgs e)
        {
            binds();
        }        private void binds()
        {
            
            string strConn = @"server=KGLTS\SQLEXPRESS;database=CathodicProtection;Trusted_Connection=SSPI";
            SqlConnection con = new SqlConnection(strConn);
            SqlDataAdapter sda = new SqlDataAdapter("select * from WorkRange where DelFlag = 0", con);
            sda.Fill(ds);            foreach (DataRow row in ds.Tables[0].Rows)
            {
                TreeNode tn = new TreeNode();
                tn.Name = row["WorkRangeID"].ToString();
                tn.Text = row["WorkRangeName"].ToString();
                treeView1.Nodes.Add(tn);                SqlDataAdapter sda2 = new SqlDataAdapter("select * from PipingInfo where WorkRangeID='" + tn.Name + "' AND DelFlag = 0", con);
                sda2.Fill(ds2);
                foreach (DataRow row2 in ds2.Tables[0].Rows)
                {
                    TreeNode tn2 = new TreeNode();
                    tn2.Name = row2["PipingID"].ToString();
                    tn2.Text = row2["PipName"].ToString();
                    treeView1.Nodes[tn.Index].Nodes.Add(tn2);
                }
                
            }
          }
    }
}这样加载出来节点会重复被加载,也就是说里面有很多相同的内容.
有没有什么好的方法来加载进去?第二个问题:
我想要里面的数据能够被拖拽,我实现了拖拽
但是我想要控制它,只能在同级里面拖拽..谢谢各位看官了.. 不答  顶顶也谢谢

解决方案 »

  1.   

    你试试用两个FOR循环代替FOREACH
      

  2.   

    同级里面拖拽的话,判断可试试node.Level这个属性
      

  3.   

    想想SQL能不能改改,用Distinct之类的,不查出重复的记录
    或者
    foreach (DataRow row2 in ds2.Tables[0].Rows)
    {
    //加个list保存row2["PipingID"],如果list里面已经有了,continue
                        TreeNode tn2 = new TreeNode();
                        tn2.Name = row2["PipingID"].ToString();
                        tn2.Text = row2["PipName"].ToString();
                        treeView1.Nodes[tn.Index].Nodes.Add(tn2);
     }
      

  4.   

    /// <summary>
            /// 初始化 RootNode DataTable
            /// </summary>
            private void InitRootNodeDataTable(string wherstr)
            {
                dataTbl1 = new DataTable();            dataTbl1 = DbAccess.GetDS("select * from page " + wherstr).Tables[0];
                //读取并将公共的分类信息添加到数据集中
                dataTbl1.TableName = "TreeView";
            }        /// <summary>
            /// 初始化树
            /// </summary>
            /// <param name="dt">取得所有的分类</param>
            private void initTree(DataTable dt)
            {
                this.tvCategory.Nodes.Clear();//先清理原先的
                if (dt != null && dt.Rows.Count == 0) return;
                DataRow[] Rows = dt.Select("Page_parent=0 ");
                if (Rows.Length == 0) return;
                foreach (DataRow row in Rows)
                {
                    TreeNode tNode = new TreeNode();
                    tNode.Value = row["Page_id"].ToString();
                    tNode.Text = row["Page_name"].ToString();
                    //tNode.NavigateUrl = "";
                    //tNode.Target = "MainFrameBS";//指向父窗体右边的那个iframe                this.tvCategory.Nodes.Add(tNode);
                    tNode.Expanded = true;
                    createChildNode(tNode, tNode.Value);
                }            ////添加一级“未分类”节点
                //TreeNode tNode1 = new TreeNode();
                //tNode1.Value = "-1";
                //tNode1.Text = "未分类";
                //tNode1.NavigateUrl = "BasicInfoConfig.aspx?Class_ID=" + tNode1.Value + "";
                //tNode1.Target = "MainFrameBS";//指向父窗体右边的那个iframe            //this.tvCategory.Nodes.Add(tNode1);
                //tNode1.Expanded = true;
            }
            /// <summary>
            /// 创建子节点
            /// </summary>
            /// <param name="node"></param>
            /// <param name="strParentNo"></param>
            private void createChildNode(TreeNode node, string strParentNo)
            {
                //string parentId="";
                DataRow[] Rows = this.dataTbl1.Select("Page_parent='" + strParentNo + "' and Page_parent<>0");
                foreach (DataRow row in Rows)
                {
                    TreeNode childNode = new TreeNode();                childNode.Value = row["Page_id"].ToString();
                    childNode.Target = "mainFrame";//指向父窗体右边的那个iframe
                    childNode.Text = row["Page_name"].ToString();
                    childNode.NavigateUrl = "~/"+row["Page_url"].ToString(); ;                node.ChildNodes.Add(childNode);                createChildNode(childNode, row["Page_id"].ToString());
                }
            }
      

  5.   

    我了个去...
    原来是我没有将dataset里面的数据清空
    它一直留在内存里面的现在解决第一个问题了大家帮我瞧瞧第二个问题
      

  6.   

    回复9楼TreeNode  r =  new TreeNode
    这r 根本就没有value这个属性别随便粘贴
      

  7.   

    兄弟,那你应该是获取它的子节点啊,treeView1.ChildNodes.Add(tn2);然后在外围循环中在把整个节点加进去!
      

  8.   


    有没有Demo呢?  还有就是我应该怎么样去获取一个父节点
      

  9.   

    3个表的关联字段是什么?
    建议你试试用 DataContext 模板生称自己的 DataContext我模拟的代码 你研究下
    // 模拟了2个 DataTable
    DataTable table1 = new DataTable();
    table1.Columns.AddRange(new DataColumn[] {
        new DataColumn("WorkRangeID"),
        new DataColumn("WorkRangeName")
    });DataTable table2 = new DataTable();
    table2.Columns.AddRange(new DataColumn[] {
        new DataColumn("PipingID"),
        new DataColumn("PipName"),
        new DataColumn("WorkRangeID")
    });TreeView tv = new TreeView();// 利用 Lambad 表达式
    var nodesLevel1 = table1.AsEnumerable()
        .Select(row => new TreeNode()
        {
            Name = row["WorkRangeID"] as string,
            Text = row["WorkRangeName"] as string
        });tv.Nodes.AddRange(nodesLevel1.ToArray());tv.BeforeExpand += (obj, args) =>
    {
        if (args.Node.Tag == null) // 一个标识,判断节点是否已被加载
        {
            var nodesLevel2 = table2.AsEnumerable()
                .Where(row => row["WorkRangeID"] as string == args.Node.Name)
                .Select(row => new TreeNode()
                {
                    Name = row["PipingID"] as string,
                    Text = row["PipName"] as string
                });
            args.Node.Nodes.AddRange(nodesLevel2.ToArray());
        }
    };
    思路:在初始化 TreeView 时,只加载顶层节点,在 TreeView.BeforeExpand 事件 中,加载被 Expand Node 的子节点Lambda 表达式
      

  10.   

    至于同层节点的拖拽TreeView.ItemDrag 事件 
    private void treeView1_DragOver(object sender, DragEventArgs e)
    {
        // Retrieve the client coordinates of the mouse position.
        Point targetPoint = treeView1.PointToClient(new Point(e.X, e.Y));    // Select the node at the mouse position.
        // treeView1.SelectedNode = treeView1.GetNodeAt(targetPoint);
        TreeNode treeNode = treeView1.GetNodeAt(targetPoint);    if(treeNode != null) // 通过 treeNode.Level 进行同层判断
    }
      

  11.   


    treeNode.Level 需要设置什么呢>
      

  12.   


    treeNode.Leve 只读属性获取 TreeView 控件中的树视图的深度(从零开始)。
    对于 Level 属性,根节点被视为嵌套的第一层,并返回 0。自已也要思考思考
      

  13.   

    拖拽需要处理ItemDrag DragEnter DragOver DragDrop这几个事件
      

  14.   

    我想要控制它,只能在同级里面拖拽..
    ——————
    这个需要在DragOver事件中进行判断,
            private const string NodeObjectName = "System.Windows.Forms.TreeNode";private void treeview1_DragOver(object sender, DragEventArgs e)
            {
                // process the drag image            if (false == e.Data.GetDataPresent(NodeObjectName, true))
                {
                    e.Effect = DragDropEffects.None;
                    return;
                }            Point pt = treeview1.PointToClient(new Point(e.X, e.Y));
                // target node is the tree node that will be dropped on
                TreeNode targetNode = treeview1.GetNodeAt(pt);
                // it is the TreeNode beging dragged (and will be dropped later)
                TreeNode dragNode = (TreeNode)e.Data.GetData(NodeObjectName);
                
                // 判断dragNode是否可以被拖拽
             
                if (targetNode != null && targetNode.Parent == dragNode.Parent)
                
                e.Effect = DragDropEffects.Move;
                else
    e.Effect = DragDropEffects.None;
            }
      

  15.   


    我是在DragDrop里面做操作的.但是还是不能判断
    private void treeView1_DragDrop(object sender, DragEventArgs e)
            {
                TreeNode myNode = null;
                if (e.Data.GetDataPresent(typeof(TreeNode)))
                {
                    myNode = (TreeNode)(e.Data.GetData(typeof(TreeNode)));
                }
                else
                {
                    MessageBox.Show("error");
                }
                Point Position = new Point();
                Position.X = e.X;
                Position.Y = e.Y;
                Position = treeView1.PointToClient(Position);
                TreeNode DropNode = this.treeView1.GetNodeAt(Position);
                // 1.目标节点不是空。2.目标节点不是被拖拽接点的字节点。3.目标节点不是被拖拽节点本身
                if (DropNode != null && DropNode.Parent != myNode && DropNode != myNode)
                {
                    TreeNode DragNode = myNode;
                    // 将被拖拽节点从原来位置删除。
                    myNode.Remove();
                    // 在目标节点下增加被拖拽节点
                    DropNode.Nodes.Add(DragNode);
                    TreeNode t = (TreeNode)e.Data.GetData(typeof(TreeNode));
                   
                    string sql = "Update PipingInfo Set WorkRangeID = '" + DropNode.Name.ToString() + "' Where PipingID = '" + t.Name.ToString() + "'";
                    SQLhelper.ExecuteNonQuery(sql);
                    
                }
                // 如果目标节点不存在,即拖拽的位置不存在节点,那么就将被拖拽节点放在根节点之下
                if (DropNode == null)
                {
                    TreeNode DragNode = myNode;
                    myNode.Remove();
                    treeView1.Nodes.Add(DragNode);
                }
            }
      

  16.   

    第一个问题是加载没有清空,另外如果不能保证树节点再数据库不唯一,
              应该再加个hashtable,重复的不构造
    第二个问题可以设置树节点的tag,通过tag值来判断节点的级数
              比如父节点tag设置为“@PARENT”
                  子节点tag设置为“@Child”
    一个原则是节点tag不要乱,一级一个就可以了
      

  17.   


    是在我创建节点foreach循环的时候就设置它的tag吗?
    能不能将就我上面贴的代码 举个例子设置给我看一下
      

  18.   

    这几个事件的作用如下:
    当你托拽一个节点然后移动鼠标时会触发dragover事件,你要在这里写代码 来决定你托的node是不是可以放在鼠标当前所指的位置,如果可以放并且你松了鼠标后才会进入dragdrop事件,在这里你要写的code就是如果把你托的node放到你鼠标所指的位置,所以你的问题应该在dragover中进行判断,只有满足你的条件后才允许drop,否则就不允许,而允许与否通过设置DragDropEffects的值,你在itemdrag事件中会调用DoDragDrop触发托拽,这时你会指定DragDropEffects,假设你指定的是Move,则在dragover中进行判断后,如果允许继续托拽就设置DragDropEffects的值为Move,设置为其他的也室为不允许托拽,也就是itemdrag和dragover中的DragDropEffects值应保持一致DoDragDrop(e.Item, DragDropEffects.Move);
      

  19.   

    foreach (DataRow row in ds.Tables[0].Rows)
                {
                    TreeNode tn = new TreeNode();
                    tn.Name = row["WorkRangeID"].ToString();
                    tn.Text = row["WorkRangeName"].ToString();
                    tn.Tag = "@PARENT";
                    treeView1.Nodes.Add(tn);                SqlDataAdapter sda2 = new SqlDataAdapter("select * from PipingInfo where WorkRangeID='" + tn.Name + "' AND DelFlag = 0", con);
                    sda2.Fill(ds2);
                    foreach (DataRow row2 in ds2.Tables[0].Rows)
                    {
                        TreeNode tn2 = new TreeNode();
                        tn2.Name = row2["PipingID"].ToString();
                        tn2.Text = row2["PipName"].ToString();
                        tn.Tag = "@CHILD";
                        treeView1.Nodes[tn.Index].Nodes.Add(tn2);
                    }
                    
                }
    这样就可以知道光标所在的节点是父节点还是子节点,
      

  20.   

    如果你只允许在同级托拽
     if (DropNode != null && DropNode.Parent != myNode && DropNode != myNode)
                {改下 if (DropNode != null && DropNode != myNode && DropNode.Parent == myNode.Parent )
                {
    Parent相同应该就是同级节点