C#根据Windows窗体中接收的数据动态创建组框

C#根据Windows窗体中接收的数据动态创建组框,c#,winforms,C#,Winforms,我目前正在开发windows窗体应用程序,我想动态创建窗体,根据类别和产品创建GroupBox。 我有两张桌子,像: +-------------------------------+ | Category | +-------------------------------+ | CategoryId (UNIQUEIDENTIFIER) | | Name (VARCHAR(255)) | | CreatedBy(VARCHAR(2

我目前正在开发windows窗体应用程序,我想动态创建窗体,根据类别和产品创建GroupBox。 我有两张桌子,像:

+-------------------------------+
|           Category            |
+-------------------------------+
| CategoryId (UNIQUEIDENTIFIER) |
| Name (VARCHAR(255))           |
| CreatedBy(VARCHAR(255))       |
| CreationDate(DATETIME)        |
+-------------------------------+


+-----------------------------+
|           Product           |
+-----------------------------+
| ProductId(UNIQUEIDENTIFIER) |
| CategoryId (FK)             |
| Name(VARCHAR(255))          |
| CreatedBy(VARCHAR(255))     |
| CreationDate(DATETIME)      |
| IsDeleted(BOOL)             |
+-----------------------------+
例如,如果我有一个类别
水果
,它的产品是
香蕉
苹果
,但我有另一个类别叫
蔬菜
,它的产品是
鳄梨
番茄
,比如:

+--------------------------------------+---------------------+-------------------------+------------------------+
|    CategoryId (UNIQUEIDENTIFIER)     | Name (VARCHAR(255)) | CreatedBy(VARCHAR(255)) | CreationDate(DATETIME) |
+--------------------------------------+---------------------+-------------------------+------------------------+
| CEF50872-B8E7-4EA0-A3D7-00048FFC82DA | Fruit               | Test                    | 10/11/2018             |
| 646B5A64-EA28-4471-8964-0017EB511797 | Vegetables          | Test                    | 10/12/2018             |
+--------------------------------------+---------------------+-------------------------+------------------------+


+--------------------------------------+--------------------------------------+---------+-------------------------+------------------------+
|     ProductId(UNIQUEIDENTIFIER)      |           CategoryId (FK)            |  Name   | CreatedBy(VARCHAR(255)) | CreationDate(DATETIME) |
+--------------------------------------+--------------------------------------+---------+-------------------------+------------------------+
| D81EFF8C-9B8D-48C9-9CC7-0015B2787D4A | CEF50872-B8E7-4EA0-A3D7-00048FFC82DA | Banana  | Test                    | 10/11/2018             |
| 7683554C-5E46-40FE-9285-001E8CD67740 | CEF50872-B8E7-4EA0-A3D7-00048FFC82DA | Apple   | Test                    | 10/11/2018             |
| 614FBE96-6355-4C3B-985B-002E2B9853CB | 646B5A64-EA28-4471-8964-0017EB511797 | Avocado | Test                    | 10/11/2018             |
| 74352B1B-36E8-4913-898E-002ED4CB21AD | 646B5A64-EA28-4471-8964-0017EB511797 | Tomato  | Test                    | 10/11/2018             |
+--------------------------------------+--------------------------------------+---------+-------------------------+------------------------+
当我在
c#
中从存储过程(如

SELECT * FROM Category AS c
INNER JOIN Product AS P ON C.CategoryId = P.CategoryId
因此,我想动态创建
groupbox
。如何根据类别及其产品创建此
groupbox
?问候

在决赛中,我想要这样的东西:

更新

我尝试以下评论:

从datatable接收数据:

  var data = db.GetTableBySQL("usp_RedMarks_Get");

    foreach (DataRow itm in data.Rows)
    {
        if (itm["CategoryName"].ToString() != CurrentGroupBoxName)
        {
            flpRedMarks.Controls.Add(GetGroupBox(itm, 200, 100));
        }
    }
创建GroupBox和项目:

 private GroupBox GetGroupBox(DataRow c, int width, int height)
        {
            GroupBox currentGroupBox = new GroupBox();
            currentGroupBox.Size = new Size(width, height);
            currentGroupBox.Text = c["CategoryName"].ToString();
            currentGroupBox.Name = c["CategoryName"].ToString();
            CurrentGroupBoxName = currentGroupBox.Name;

            var y = 20;
            foreach (var itm in c.Table.Rows)
            {
                CheckBox cb = new CheckBox();
                cb.Text = itm.ToString();
                cb.Location = new Point(5, y);
                // you can add an event here...
                //cb.CheckedChanged += cb_SomeEvent;
                currentGroupBox.Controls.Add(cb);
                y += 20;
            }

            return currentGroupBox;
        }
我从SQL接收数据,如:

但我得到的不是基于类别的项目(产品),而是合并的数据:


我做错了什么?如果您可以像下面这样向存储过程中添加and ORDER BY子句,请注意:

SELECT C.Name AS 'CategoryName', P.Name AS 'SubcategoryName'
FROM Category AS C
INNER JOIN Product AS P ON C.CategoryId = P.CategoryId
ORDER BY C.Name
然后,您可以像下面这样迭代返回的数据行。请注意,我在组框中添加了一个流面板,以避免需要保留偏移量变量

GroupBox currentGroupBox = new GroupBox();
FlowLayoutPanel currentGroupBoxPanel = null;
foreach (DataRow itm in _data.Rows)
{
    var currentCategoryName = itm["CategoryName"].ToString();
    if (currentCategoryName != currentGroupBox.Name)
    {
        currentGroupBox = new GroupBox();
        currentGroupBox.Name = currentCategoryName;
        currentGroupBoxPanel = new FlowLayoutPanel();
        currentGroupBoxPanel.FlowDirection = FlowDirection.TopDown;
        currentGroupBoxPanel.Dock = DockStyle.Fill;
        currentGroupBox.Controls.Add(currentGroupBoxPanel);
        flpRedMarks.Controls.Add(currentGroupBox);
    }
    var cb = new CheckBox();
    cb.Text = itm["SubcategoryName"].ToString();
    currentGroupBoxPanel.Controls.Add(cb);
}

如果可以向存储过程中添加and ORDER BY子句,如下所示:

SELECT C.Name AS 'CategoryName', P.Name AS 'SubcategoryName'
FROM Category AS C
INNER JOIN Product AS P ON C.CategoryId = P.CategoryId
ORDER BY C.Name
然后,您可以像下面这样迭代返回的数据行。请注意,我在组框中添加了一个流面板,以避免需要保留偏移量变量

GroupBox currentGroupBox = new GroupBox();
FlowLayoutPanel currentGroupBoxPanel = null;
foreach (DataRow itm in _data.Rows)
{
    var currentCategoryName = itm["CategoryName"].ToString();
    if (currentCategoryName != currentGroupBox.Name)
    {
        currentGroupBox = new GroupBox();
        currentGroupBox.Name = currentCategoryName;
        currentGroupBoxPanel = new FlowLayoutPanel();
        currentGroupBoxPanel.FlowDirection = FlowDirection.TopDown;
        currentGroupBoxPanel.Dock = DockStyle.Fill;
        currentGroupBox.Controls.Add(currentGroupBoxPanel);
        flpRedMarks.Controls.Add(currentGroupBox);
    }
    var cb = new CheckBox();
    cb.Text = itm["SubcategoryName"].ToString();
    currentGroupBoxPanel.Controls.Add(cb);
}

我将使用
flowLayoutPanel
控件来设置分组框的间距。 然后,您可以编写一个逻辑来动态创建
groupbox
元素

以下是实现此任务的一种方法:

namespace WindowsFormsApplication47
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            var dataFromDb = GetData();
            foreach (var itm in dataFromDb)
            {
                flowLayoutPanel1.Controls.Add(GetGroupBox(itm, 200, 100));
            }
        }

        private GroupBox GetGroupBox(Category c,int width,int height)
        {
            GroupBox g = new GroupBox();
            g.Size = new Size(width, height);
            g.Text = c.Name;

            var y = 20;
            foreach (var itm in c.Items)
            {
                CheckBox cb = new CheckBox();
                cb.Text = itm;
                cb.Location = new Point(5, y);
                // you can add an event here...
                cb.CheckedChanged += cb_SomeEvent;
                g.Controls.Add(cb);
                y += 20;
            }

            return g;
        }

        private void cb_SomeEvent(object sender, EventArgs e)
        {
            throw new NotImplementedException();
        }

        private List<Category> GetData()
        {
            // Just to simulate a database...
            Category c1 = new Category("Fruit", new List<string>() { "Banana", "Apple" });
            Category c2 = new Category("Vegetables", new List<string>() { "Avocado", "Tomato" });
            Category c3 = new Category("Programming Languages", new List<string>() { "C#", "Visual Basic" });
            Category c4 = new Category("Stars", new List<string>() { "Venus", "Mars" });

            List<Category> result = new List<Category>();
            result.Add(c1);
            result.Add(c2);
            result.Add(c3);
            result.Add(c4);

            return result;
        }
    }

    class Category
    {
        public string Name;
        public List<string> Items;

        public Category(string name,List<string> items)
        {
            this.Name = name;
            this.Items = items;
        }
    }
}

我将使用
flowLayoutPanel
控件来设置分组框的间距。 然后,您可以编写一个逻辑来动态创建
groupbox
元素

以下是实现此任务的一种方法:

namespace WindowsFormsApplication47
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            var dataFromDb = GetData();
            foreach (var itm in dataFromDb)
            {
                flowLayoutPanel1.Controls.Add(GetGroupBox(itm, 200, 100));
            }
        }

        private GroupBox GetGroupBox(Category c,int width,int height)
        {
            GroupBox g = new GroupBox();
            g.Size = new Size(width, height);
            g.Text = c.Name;

            var y = 20;
            foreach (var itm in c.Items)
            {
                CheckBox cb = new CheckBox();
                cb.Text = itm;
                cb.Location = new Point(5, y);
                // you can add an event here...
                cb.CheckedChanged += cb_SomeEvent;
                g.Controls.Add(cb);
                y += 20;
            }

            return g;
        }

        private void cb_SomeEvent(object sender, EventArgs e)
        {
            throw new NotImplementedException();
        }

        private List<Category> GetData()
        {
            // Just to simulate a database...
            Category c1 = new Category("Fruit", new List<string>() { "Banana", "Apple" });
            Category c2 = new Category("Vegetables", new List<string>() { "Avocado", "Tomato" });
            Category c3 = new Category("Programming Languages", new List<string>() { "C#", "Visual Basic" });
            Category c4 = new Category("Stars", new List<string>() { "Venus", "Mars" });

            List<Category> result = new List<Category>();
            result.Add(c1);
            result.Add(c2);
            result.Add(c3);
            result.Add(c4);

            return result;
        }
    }

    class Category
    {
        public string Name;
        public List<string> Items;

        public Category(string name,List<string> items)
        {
            this.Name = name;
            this.Items = items;
        }
    }
}


你被卡在哪一部分?通过类别循环?创建分组框?向它们添加项目?在c#中,我不知道如何将产品分组到它们的类别中,以及如何创建groupbox来创建结构:category=groupbox(文本和名称),以及groupbox@Dstanley中的产品您可能最好使用动态控件,如a。这的最终用途是,每个产品都有一个复选框,所以,这就是为什么我想作为组框,我上传了一张关于我的问题的图片,以便更清楚@DourHighArch@Jonathan. 我更新了答案中的代码,以更好地适应您更新的问题。这里的问题是调用
GetGroupBox()
四次,每次调用都会循环返回所有八行结果。您看到的标签是错误的,因为您使用
itm.ToString()
获取子类别名称,而不是使用
itm[“subcategory name”].ToString()
。希望这能帮上忙。你被卡在哪一部分?通过类别循环?创建分组框?向它们添加项目?在c#中,我不知道如何将产品分组到它们的类别中,以及如何创建groupbox来创建结构:category=groupbox(文本和名称),以及groupbox@Dstanley中的产品您可能最好使用动态控件,如a。这的最终用途是,每个产品都有一个复选框,所以,这就是为什么我想作为组框,我上传了一张关于我的问题的图片,以便更清楚@DourHighArch@Jonathan. 我更新了答案中的代码,以更好地适应您更新的问题。这里的问题是调用
GetGroupBox()
四次,每次调用都会循环返回所有八行结果。您看到的标签是错误的,因为您使用
itm.ToString()
获取子类别名称,而不是使用
itm[“subcategory name”].ToString()
。希望这能帮上忙。看来它行得通,我稍后会测试,如果行得通,我会把它标记为正确答案,非常感谢你们,并和圣诞节结婚!它似乎是有效的,我稍后测试并标记为正确答案,如果它有效的话,非常感谢你和圣诞节结婚!是否可以使用Datatable代替列表?那么我如何从datatable中指定此产品属于此类别?是的,只需在datatable中输入,就像您在列表中输入一样。如果你想举个例子的话,我可以明天再去。我真的很感激。。我已经使用我的问题更新了我的问题DataTable@Jonathan我已经更新了我的答案,并建议直接使用
datatable
。请参阅“更新”部分。是否可以使用Datatable代替列表?那么我如何从datatable中指定此产品属于此类别?是的,只需在datatable中输入,就像您在列表中输入一样。如果你想举个例子的话,我可以明天再去。我真的很感激。。我已经使用我的问题更新了我的问题DataTable@Jonathan我已经更新了我的答案,并建议直接使用
datatable
。请参阅“更新”部分。