【问题标题】:For a .NET winforms datagridview I would like a combobox column to have a different set of values for each row对于 .NET winforms datagridview,我希望组合框列的每一行都有一组不同的值
【发布时间】:2011-06-16 20:06:22
【问题描述】:

我有一个绑定到 POCO 的 DataGridView。我的数据绑定工作正常。但是,我添加了一个组合框列,我希望每一行都不同。具体来说,我有一个购买物品的网格,其中一些有尺寸(如成人 XL、成人 L),而其他物品没有尺寸(如汽车磁铁)。

所以本质上我想要更改的是数据网格中组合框列的数据源。可以这样做吗?

我可以挂钩哪些事件以允许我更改每行的某些列的属性?一种可接受的替代方法是在用户单击或使用选项卡进入行时更改属性。那是什么活动?

赛斯

编辑
我需要更多关于这个问题的帮助。在 Triduses 的帮助下,我非常接近,但我需要更多信息。

首先,根据问题,CellFormatting 事件是否真的是更改组合框列的 DataSource 的最佳/唯一事件。我问是因为我正在做一些资源/数据密集型的事情,而不仅仅是格式化单元格。

其次,只需将鼠标悬停在单元格上即可调用单元格格式化事件。我尝试在 if-block 中设置 FormattingApplied 属性,然后在 if-test 中检查它,但这会返回一条奇怪的错误消息。我的理想情况是,我会为每一行应用更改组合框的数据源一次,然后完成。

最后,为了设置组合框列的数据源,我必须能够将 if 块中的 Cell 转换为 DataGridViewComboBoxColumn 类型,以便我可以用行填充它或设置数据源或其他东西。这是我现在拥有的代码。

Private Sub ProductsDataGrid_CellFormatting(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellFormattingEventArgs) Handles ProductsDataGrid.CellFormatting

    If e.ColumnIndex = ProductsDataGrid.Columns("SizeDGColumn").Index Then ' AndAlso Not e.FormattingApplied Then
        Dim product As LeagueOrderProductInfo = DirectCast(ProductsDataGrid.Rows(e.RowIndex).DataBoundItem, LeagueOrderProductInfo)
        Dim sizes As LeagueOrderProductSizeList = product.ProductSizes
        sizes.RemoveSizeFromList(_parentOrderDetail.SizeID)

        'WHAT DO I DO HERE TO FILL THE COMBOBOX COLUMN WITH THE sizes collection.

    End If

End Sub

请帮忙。我完全被卡住了,这个任务项目应该需要一个小时,而我现在已经 4 个多小时了。顺便说一句,我也愿意通过采取完全不同的方向来解决这个问题(只要我能很快完成。)

赛斯

【问题讨论】:

    标签: .net visual-studio winforms visual-studio-2010 datagridview


    【解决方案1】:

    您可以通过CellBeginEdit 事件来做到这一点。处理事件,检查正在编辑的列是否是您的 DataGridViewComboBox 列并更改组合框中的项目。

    如果您将数据源绑定到组合框,这可能不起作用。我只尝试过手动添加项目列表:

    void grid_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
    {
        if (grid.Columns[e.ColumnIndex].Name == "MyComboColumn")
        {
            // get the value of a different cell in this row that will be used to determine which values are in the combobox
            string other_value = grid[0, e.RowIndex].Value.ToString();
    
            // get the combobox cell being edited
            DataGridViewComboBoxCell cell = (DataGridViewComboBoxCell)grid[e.ColumnIndex, e.RowIndex];
    
            // update the list of items in the combobox
            cell.Items.Clear();
            if (other_value == "something")
                cell.Items.AddRange(new object[] { "Value1", "Value2" });
            else
                cell.Items.AddRange(new object[] { "Value3", "Value4" });
    
        }
    }
    

    注意:此代码未经测试,我目前不在我的开发机器上。

    【讨论】:

      【解决方案2】:

      如果您无法向此网格添加行,您可以使用事件 DataBindingComplete,当网格完成数据绑定时触发此事件,如果您可以添加行,则必须使用事件 NewRowNeeded 此事件当你点击网格底部的新行时被触发 并且您不必担心多次填充相同的组合

      【讨论】:

        【解决方案3】:

        我没有采取捕获事件来更改组合框中每行显示值的方式...看看这种方法(示例),它非常简单易行,并且完全符合您的要求恕我直言:

        1. 声明一个具有两个简单属性(名称、类型)的 Item 类

        2. 创建一个包含两列的 DataGridView(一列用于 Name,第二列用于 Type,ColumnType = DataGridViewComboBoxColumn 且 dataPropertyName = Type)

        3. 将您的(我假设的)poco 列表“附加”到 DataGridView

        4. 然后只在你的行集合中循环一次; 获取该行的 DataGridViewComboBoxColumn; 根据您对该行中 poco 的条件更改它的 items 属性

        我让你来获取特定行的 poco,或者从行中的硬编码列中读取一些属性...

        这里有一些示例代码:

        namespace DataGridViewCustomComboboxItemsPerRow
        {
            public partial class Form1 : Form
            {
                public Form1()
                {
                    InitializeComponent();
        
                    List<int> types = new List<int>();
                    List<Item> items = new List<Item>();
                    Item item;
                    for (int i = 0; i < 100; i++)
                    {
                        item = new Item();
                        item.Name = "Item" + i.ToString();
                        item.Type = i;
        
                        items.Add(item);
                        types.Add(i);
                    }
        
                    //typeDataGridViewComboBoxColumn.DataSource = types;
                    itemBindingSource.DataSource = items;
                }
        
                private void Form1_Shown(object sender, EventArgs e)
                {
                    DataGridViewComboBoxCell dgvc;
        
                    for (int i = 0; i < dataGridView1.Rows.Count; i++)
                    {
                        dgvc = (DataGridViewComboBoxCell)dataGridView1.Rows[i].Cells[1];
        
                        // Your CUSTOM code here, I just did some stupid thing here...
                        dgvc.Items.Add(i - 1);
                        dgvc.Items.Add(i);
                        dgvc.Items.Add(i + 1);
                    }
                }
            }
        
            public class Item
            {
                private string _name;
                private int _type;
        
                public string Name
                {
                    get { return _name; }
                    set { _name = value; }
                }
        
                public int Type
                {
                    get { return _type; }
                    set { _type = value; }
                }
            }
        }
        

        代码是用 C# 编写的,但非常基本,所以我想它不会在 VB.NET 中引起问题。而且这段代码确实做了一个一次性循环 (O(n)) 来为不同的行配置你的组合,而不是完成。

        希望这会有所帮助。乔普。

        【讨论】:

        【解决方案4】:

        我不确定这对您是否可行。 你能在dataGridView1_DataBindingComplete事件中尝试同样的方法吗

        foreach (DataGridViewRow var in dataGridView1.Rows)
        {
              if (var.Cells[0] is DataGridViewComboBoxCell)
              {
                  (var.Cells[0] as DataGridViewComboBoxCell).Items.Add("first col values");
              }
              if (var.Cells[1] is DataGridViewComboBoxCell)
              {
                  (var.Cells[1] as DataGridViewComboBoxCell).Items.Add("second col values");
              }
        }
        

        【讨论】:

          【解决方案5】:

          不幸的是,没有一个。您将不得不使用CellFormatting event

          这将对每个单元格触发,但您可以通过检查单元格的列索引来确定您是否在正确的列中,然后您可以在您想要工作的列中执行您的逻辑与。

          如果您决定要在他们选择行而不是显示行时更改它,您可以改用 RowEnter。

          以下是如何使用此事件的代码示例。这将列设置为在其中包含图像。

           Private Sub dgActiveOccurrences_CellFormatting(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellFormattingEventArgs) Handles dgActiveOccurrences.CellFormatting
                  If e.ColumnIndex = dgActiveOccurrences.Columns("colActiveUnreadFlag").Index Then
                      Dim occ As Occurrence = DirectCast(dgActiveOccurrences.Rows(e.RowIndex).DataBoundItem, Occurrence)
                      If occ.LastReadBy <> OccurrenceSession.Self.UserManager.MyStaffRecord.StaffId Then
                          e.Value = My.Resources.Icon_UnreadFlag
                      End If
                  End If
          End Sub
          

          【讨论】:

          • 你可以做一个代码sn-p吗?具体来说,我想我必须将 sender 转换为某些东西,然后获取列索引。对吗?
          • 或者看起来我使用了事件参数。它有一个列索引。
          猜你喜欢
          • 2014-07-21
          • 1970-01-01
          • 2017-02-28
          • 1970-01-01
          • 2014-06-20
          • 2023-02-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多