代码之家  ›  专栏  ›  技术社区  ›  AT-2017

在每个循环迭代中创建对象

  •  4
  • AT-2017  · 技术社区  · 7 年前

    我使用的是内置的z80导航控制,下面是演示链接: Z80 Navigation Menu

    如果有人看到该控件,它有一个对象来创建类似父菜单的菜单,并在其下创建子菜单。如下所示:

    public List<NavBarItem> sampleDynamicNav; //List of navbar objects
    public DemoItems()
    {
        //Create object instance here and assign the parent as well child menus here
        sampleDynamicNav = new List<NavBarItem> {
        new NavBarItem {ID = 1, Text = "UserInfo", Icon = new ItemIcon {Default = SampleProject.Properties.Resources.nav_new_home, Hover = SampleProject.Properties.Resources.nav_new_home, Selected = SampleProject.Properties.Resources.nav_new_home}, ToolTip = "tooltip Main Menu", Height = 40,
            Icon = new ItemIcon {Default = SampleProject.Properties.Resources.nav_new_home, Hover = SampleProject.Properties.Resources.nav_new_home, Selected = SampleProject.Properties.Resources.nav_new_home }, ToolTip = "tooltip Desktop"},
            Childs = new List<NavBarItem> {
                        new NavBarItem {ID = 41, Text = "Add/Edit Users", Height = 30 },
                        new NavBarItem {ID = 42, ParentID = 1, Text = "Inactive User", Height = 30}
        };
    }
    

    如果我们静态地分配菜单,这是非常简单的。但我坚持这样做,当尝试动态添加它们时,我的意思是从数据库中创建菜单,如下所示:

    public DemoItems()
    {
        foreach (var parent in GetParent("USER-0001"))
        {
              foreach (var child in GetChild(parent.MenuNo))
              {
                sampleDynamicNav = new List<NavBarItem> {
                     new NavBarItem {
                     ID = parent.MenuNo, Text = parent.MenuName, Icon = new ItemIcon {Default =  SampleProject.Properties.Resources.nav_new_home, Hover = SampleProject.Properties.Resources.nav_new_home, Selected = SampleProject.Properties.Resources.nav_new_home}, ToolTip = "tooltip Main Menu", Height = 40,
                     Childs = new List<NavBarItem> {
                                        new NavBarItem {ID = child.MenuNo, ParentID = parent.MenuNo, Text = child.MenuName, Height = 30 },
                               }
                         }
                   };
              }
         }
    }
    

    Sample 1

    但是它应该是如下所示的,因为有两个父菜单,并使用 foreach 循环:

    Sample 2

    我不知道是否还需要做其他事情,我想知道是否可以循环浏览导航栏的子属性,如下所示:

    foreach (var child in GetChild(parent.MenuNo))
    {
       Childs = new List<NavBarItem> {
                new NavBarItem {ID = child.MenuNo, ParentID = parent.MenuNo, Text = child.MenuName, Height = 30 },
    }
    

    请注意 :当尝试使用循环迭代子属性时,它立即抛出错误。第二个内循环工作,并取出子菜单,但也就是说,父菜单有两个子菜单,每次返回1。我调试了列表,它像往常一样返回双亲菜单,但没有显示在导航栏中。

    GetParents方法 :

    /**Get Menu Details - Starts**/
    public IEnumerable<UserViewModel> GetParent(string empNo)
    {
           List<UserViewModel> lstUser = new List<UserViewModel>();
    
           string query = "SELECT DISTINCT M.PARENT, M.MENUNO, M.MENUNAME FROM (SELECT DISTINCT M.MENUNO, M.MENUNAME, M.PARENT " +
                          "FROM USER_DETAILS U INNER JOIN USER_GROUP_DETAILS UG ON UG.EMPNO = U.EMPNO " +
                          "INNER JOIN ASSIGN_MENU_DETAILS AM ON AM.GROUPNO = UG.GROUPNO INNER JOIN MENU_DETAILS M " +
                          "ON M.MENUNO = AM.MENUNO WHERE U.EMPNO = '" + empNo + "' " +
                          "UNION ALL " +
                          "SELECT DISTINCT M.MENUNO, M.MENUNAME, " +
                          "M.PARENT FROM MENU_DETAILS M " +
                          "INNER JOIN MENU_DETAILS C " +
                          "ON C.PARENT = M.MENUNO) m WHERE M.PARENT = '0' ORDER BY M.PARENT";
    
            DataTable dt = SelectData(query);
    
            if (dt != null && dt.Rows.Count > 0)
            {
                foreach (DataRow dr in dt.Rows)
                {
                    UserViewModel bo = new UserViewModel();
                    bo.Parent = Convert.ToInt32(dr["PARENT"].ToString());
                    bo.MenuNo = Convert.ToInt32(dr["MENUNO"].ToString());
                    bo.MenuName = dr["MENUNAME"].ToString();
    
                    lstUser.Add(bo);
                }
            }
       return lstUser;
    }
    /**Get Menu Details - Ends**/
    
    2 回复  |  直到 7 年前
        1
  •  3
  •   Reza Aghaei    7 年前

    您可以创建以下帮助器方法并使用它们创建 List<NavBarItem 接受任何类型的数据源作为输入,包括 DataTable List<YourEntity> 或者任何其他 IEnumerable<T> .

    它依赖于递归算法来创建树。要从任何类型的数据源创建树,您需要具备以下信息:

    1. 数据源
    2. 如何在数据源中查找项的子项

    下面的方法创建一个 NavBarItem 通过询问上述信息来确定层次结构:

    private IEnumerable<NavBarItem> GetNavBarItems<T>(
        IEnumerable<T> source,
        Func<T, Boolean> isRoot,
        Func<T, IEnumerable<T>, IEnumerable<T>> getChilds,
        Func<T, NavBarItem> getItem)
    {
        IEnumerable<T> roots = source.Where(x => isRoot(x));
        foreach (T root in roots)
            yield return ConvertEntityToNavBarItem(root, source, getChilds, getItem); ;
    }
    
    private NavBarItem ConvertEntityToNavBarItem<T>(
        T entity,
        IEnumerable<T> source,
        Func<T, IEnumerable<T>, IEnumerable<T>> getChilds,
        Func<T, NavBarItem> getItem)
    {
        NavBarItem node = getItem(entity);
        var childs = getChilds(entity, source);
        foreach (T child in childs)
            node.Childs.Add(ConvertEntityToNavBarItem(child, source, getChilds, getItem));
        return node;
    }
    

    var dt = new DataTable();
    dt.Columns.Add("Id", typeof(int));
    dt.Columns.Add("Name", typeof(string));
    dt.Columns.Add("ParentId", typeof(int));
    
    dt.Rows.Add(1, "Menu 1", DBNull.Value);
    dt.Rows.Add(11, "Menu 1-1", 1);
    dt.Rows.Add(111, "Menu 1-1-1", 11);
    dt.Rows.Add(112, "Menu 1-1-2", 11);
    dt.Rows.Add(12, "Menu 1-2", 1);
    dt.Rows.Add(121, "Menu 1-2-1", 12);
    dt.Rows.Add(122, "Menu 1-2-2", 12);
    dt.Rows.Add(123, "Menu 1-2-3", 12);
    dt.Rows.Add(124, "Menu 1-2-4", 12);
    dt.Rows.Add(2, "Menu 2", DBNull.Value);
    dt.Rows.Add(21, "Menu 2-1", 2);
    dt.Rows.Add(211, "Menu 2-1-1", 21);
    

    然后将其转换为 List<NavBarItem> ,您可以使用以下代码:

    var source = dt.AsEnumerable();
    var list = GetNavBarItems(
            source,
            (r) => r.Field<int?>("ParentId") == null,
            (r, s) => s.Where(x => x.Field<int?>("ParentId") == r.Field<int?>("Id")),
            (r) => new NavBarItem()
            {
                ID = r.Field<int>("Id"),
                Text = r.Field<string>("Name"),
                ParentID = r.Field<int?>("ParentId")
            }).ToList();
    

    Menu 1
       Menu 1-1
           Menu 1-1-1
           Menu 1-1-2
       Menu 1-2
           Menu 1-2-1
           Menu 1-2-2
           Menu 1-2-3
           Menu 1-2-4
    Menu 2
        Menu 2-1
            Menu 2-1-1
    

    对于那些不想安装软件包但想测试结构的人,可以使用以下方法 导航天线 类别:

    public class NavBarItem
    {
        public NavBarItem()
        {
            Childs = new List<NavBarItem>();
        }
        public int ID { get; set; }
        public int? ParentID { get; set; }
        public string Text { get; set; }
        public List<NavBarItem> Childs { get; set; }
        public override string ToString()
        {
            return Text;
        }
    }
    
        2
  •  1
  •   AT-2017    7 年前

    我用您的代码示例@Reza Aghaei尝试了以下内容,并使用 TreeView 控件如下所示:(它可以工作,但在下面的一行中出现错误)

    private void frmSampleApp_Load(object sender, EventArgs e)
    {
        var dt = new DataTable();
        dt.Columns.Add("Id", typeof(int));
        dt.Columns.Add("Name", typeof(string));
        dt.Columns.Add("ParentId", typeof(int));
    
        dt.Rows.Add(1, "Menu 1", DBNull.Value);
        dt.Rows.Add(11, "Menu 1-1", 1);
        dt.Rows.Add(111, "Menu 1-1-1", 11);
        dt.Rows.Add(112, "Menu 1-1-2", 11);
        dt.Rows.Add(12, "Menu 1-2", 1);
        dt.Rows.Add(121, "Menu 1-2-1", 12);
        dt.Rows.Add(122, "Menu 1-2-2", 12);
        dt.Rows.Add(123, "Menu 1-2-3", 12);
        dt.Rows.Add(124, "Menu 1-2-4", 12);
        dt.Rows.Add(2, "Menu 2", DBNull.Value);
        dt.Rows.Add(21, "Menu 2-1", 2);
        dt.Rows.Add(211, "Menu 2-1-1", 21);
    
        var source = dt.AsEnumerable();
        var list = GetNavBarItems(
                source,
                (r) => r.Field<int?>("ParentId") == null,
                (r, s) => s.Where(x => x.Field<int?>("ParentId") == r.Field<int?>("Id")),
                (r) => new NavBarItem()
                {
                    ID = r.Field<int>("Id"),
                    Text = r.Field<string>("Name"),
                    ParentID = r.Field<int?>("ParentId")
                }).ToList();
    
        foreach (var item in list)
        {
            TreeNode parentNode = null;
            parentNode = treeView1.Nodes.Add(item.Text.ToString());
    
            BindData(Convert.ToInt32(item.ParentID), parentNode);
        }
    }
    
    public void BindData(int parentId, TreeNode parentNode)
    {
        var dt = new DataTable();
        dt.Columns.Add("Id", typeof(int));
        dt.Columns.Add("Name", typeof(string));
        dt.Columns.Add("ParentId", typeof(int));
    
        dt.Rows.Add(1, "Menu 1", DBNull.Value);
        dt.Rows.Add(11, "Menu 1-1", 1);
        dt.Rows.Add(111, "Menu 1-1-1", 11);
        dt.Rows.Add(112, "Menu 1-1-2", 11);
        dt.Rows.Add(12, "Menu 1-2", 1);
        dt.Rows.Add(121, "Menu 1-2-1", 12);
        dt.Rows.Add(122, "Menu 1-2-2", 12);
        dt.Rows.Add(123, "Menu 1-2-3", 12);
        dt.Rows.Add(124, "Menu 1-2-4", 12);
        dt.Rows.Add(2, "Menu 2", DBNull.Value);
        dt.Rows.Add(21, "Menu 2-1", 2);
        dt.Rows.Add(211, "Menu 2-1-1", 21);
    
        var source = dt.AsEnumerable();
        var list = GetNavBarItems(
                source,
                (r) => r.Field<int?>("ParentId") == null,
                (r, s) => s.Where(x => x.Field<int?>("ParentId") == r.Field<int?>("Id")),
                (r) => new NavBarItem()
                {
                    ID = r.Field<int>("Id"),
                    Text = r.Field<string>("Name"),
                    ParentID = r.Field<int?>("ParentId")
                }).ToList();
            TreeNode childNode; 
    
        foreach (var item in list)
        {
            if (parentNode == null)
    
                childNode = treeView1.Nodes.Add(item.Text.ToString());
    
            else
    
                childNode = parentNode.Nodes.Add(item.Text.ToString());
            BindData(Convert.ToInt32(item.ID.ToString()), childNode); //An unhandled exception of type 'System.StackOverflowException' occurred in System.Windows.Forms.dll
        }
    }
    
    private IEnumerable<NavBarItem> GetNavBarItems<T>(
    IEnumerable<T> source,
    Func<T, Boolean> isRoot,
    Func<T, IEnumerable<T>, IEnumerable<T>> getChilds,
    Func<T, NavBarItem> getItem)
        {
            IEnumerable<T> roots = source.Where(x => isRoot(x));
            foreach (T root in roots)
                yield return ConvertEntityToNavBarItem(root, source, getChilds, getItem); ;
        }
    
        private NavBarItem ConvertEntityToNavBarItem<T>(
        T entity,
        IEnumerable<T> source,
        Func<T, IEnumerable<T>, IEnumerable<T>> getChilds,
        Func<T, NavBarItem> getItem)
        {
            NavBarItem node = getItem(entity);
            var childs = getChilds(entity, source);
            foreach (T child in childs)
                node.Childs.Add(ConvertEntityToNavBarItem(child, source, getChilds, getItem));
            return node;
        }
    }
    
    public class NavBarItem
    {
        public NavBarItem()
        {
            Childs = new List<NavBarItem>();
        }
        public int ID { get; set; }
        public int? ParentID { get; set; }
        public string Text { get; set; }
        public List<NavBarItem> Childs { get; set; }
        public override string ToString()
        {
            return Text;
        }
    }
    

    请注意 :没关系。我知道,这里真是一团糟,只是为了学习而想弄明白而已——谢谢。