确定DataGridView中除新行

时间:2015-10-08 15:55:31

标签: c# vb.net winforms datagridview

如何确定DataGridView 中除新行(带星号的行)之外的行数?

如果我开始输入新行然后按 Esc 取消它,则同时创建的另一个新行将消失,原始行将再次成为新行。但它不再将IsNewRow属性设置为trueDataGridView.NewRowIndex突然设置为-1

如何正确计算除新行以外的行,包括上述特殊情况?Temporary reset of NewRowIndex to -1 (also affecting IsNewRow) is a "feature" of DataGridView.

(C#或VB - 无论你喜欢什么。)

对于那些无法找到上述特殊情况的人 -
只需处理DataGridView.UserDeletedRow即可:

 
Sub DataGridView1_UserDeletedRow1(sender As Object, e As EventArgs) _
        Handles DataGridView1.UserDeletedRow

    ' reveal problem with DataGridView1.NewRowIndex
    Debug.Print($"NewRowIndex={DataGridView1.NewRowIndex}")

    ' reveal problem with row.IsNewRow
    For Each row As DataGridViewRow In DataGridView1.Rows
        Debug.Print($"Row {row.Index}: IsNewRow={row.IsNewRow}")
    Next
End Sub

步骤:

  1. 创建WinForms VB项目。
  2. 添加DataGridView1
  3. DataGridView1
  4. 中添加2个文本列
  5. 添加上述事件处理程序。
  6. 启动。
  7. 关注第一列并输入a
  8. Esc
  9. 立即退出编辑模式
  10. 查看结果。上面的处理程序打印NewRowIndex=-1,但它应打印数字>= 0。上次IsNewRow值为false,但应为true

4 个答案:

答案 0 :(得分:2)

在MSDN上查看此帖子:system.windows.forms.datagridview.allowusertoaddrows仔细阅读“备注”部分)和此MSDN论坛帖子datagridview-cancel-add-new-row

您可以使用DataGridView.AllowNew属性作为解决方案的解决方法。

  1. 设置DataGridView.AllowNew = False
    这应该删除新的插入行

  2. 计算DataGridView行
    DataGridView.Rows.CountDataGridView.RowCount(以您的要求为准)

  3. 再次设置DataGridView.AllowNew = True以显示添加新记录的空白行(如果需要)

  4. 我没有测试过代码段,但这应该可以解决问题

    修改
    刚刚找到另外两篇与您的问题相关的文章,可能对您的阅读有用:

    1. adding-a-new-row-to-the-datagridview-programmatically-datagridviewallowusertoaddrow-false

    2. how-to-cancel-an-add-new-by-pressing-escape

答案 1 :(得分:2)

这是设计(confirmed by the Microsoft)。需要使用变通方法计算来实现结果。

除了特殊情况外,没有其他事件(已使用DataGridView.UserDeletedRow)适合计算。在那种情况下,关键值为temporarily incorrect – see the source

唯一的方法似乎是从DataGridViewDataGridViewRow的.NET参考源进行计算。

以下计算假设

  • 当且仅当DataGridView.AllowUserToAddRowstrue时才会出现新行。
  • 如果存在新行,则始终将其定位为最后一条记录。

让我们计算:

除新行

外的行数
= DataGridView1.Rows.Count - (DataGridView1.AllowUserToAddRows ? 1 : 0)

与有问题的原始属性不同,这些计算似乎始终成功:

DataGridView.NewRowIndex

= (DataGridView1.AllowUserToAddRows ? DataGridView1.Rows.Count - 1 : -1)

DataGridViewRow.IsNewRow

= row.DataGridView.AllowUserToAddRows && (row.Index == row.DataGridView.Rows.Count - 1)

实施为扩展方法:

''' <summary>
''' Row count including only standard rows, i.e. without new row.
''' </summary>
<Extension>
<DebuggerStepThrough>
Function StandardRowCountᛎ(dataGridView As DataGridView) As Integer
    Return dataGridView.Rows.Count - If(dataGridView.AllowUserToAddRows, 1, 0)
End Function

''' <summary>
''' The same as <see cref="DataGridView.NewRowindex"/> but reliable also after cancelled new record.
''' </summary>
<Extension>
<DebuggerStepThrough>
Function NewRowIndexᛎ(dataGridView As DataGridView) As Integer
    Return If(dataGridView.AllowUserToAddRows, dataGridView.Rows.Count - 1, -1)
End Function

''' <summary>
''' The same as <see cref="DataGridViewRow.IsNewRow"/> but reliable also after cancelled new record.
''' </summary>
<Extension>
<DebuggerStepThrough>
Function IsNewRowᛎ(row As DataGridViewRow) As Boolean
    Return row.DataGridView.AllowUserToAddRows AndAlso row.Index = row.DataGridView.Rows.Count - 1
End Function

通过调用这些方法替换标准调用后,我注意到我的项目中修复了其他几个微妙的错误,这似乎与新记录行的存在有关。

答案 2 :(得分:1)

你可以使用类似的东西

DataGridView dg = ...;
var rowCount = dg.Rows.GetRowCount(DataGridViewElementStates.Visible) -
    (dg.NewRowIndex >= 0 ? 1 : 0);

我已经在绑定和非绑定模式下测试了它并且它可以正常工作。顺便说一句,我无法重现您提到的特殊情况 - IsNewRow属性总是返回正确的值。

这是我的测试代码:

//#define fBoundMode

using System;
using System.ComponentModel;
using System.Windows.Forms;

namespace Samples
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            var form = new Form();
            var dg = new DataGridView { Dock = DockStyle.Fill, Parent = form };
#if fBoundMode
            dg.DataSource = new BindingList<Data>();
#else
            dg.Columns.Add("Foo", "Foo");
            dg.Columns.Add("Bar", "Bar");
#endif
            var status = new Label { Dock = DockStyle.Bottom, AutoSize = false, Parent = form };
            var timer = new Timer { Interval = 250, Enabled = true };
            timer.Tick += (sender, e) =>
            {
                var rowCount = dg.Rows.GetRowCount(DataGridViewElementStates.Visible) - (dg.NewRowIndex >= 0 ? 1 : 0);
                status.Text = "Rows: " + rowCount;
            };
            Application.Run(form);
        }
#if fBoundMode
        class Data
        {
            public string Foo { get; set; }
            public string Bar { get; set; }
        }
#endif
    }
}

更新:至于特殊情况(你应该从头开始明确提供 - 事件现在直到有人点击代码示例时才明确,我不认为这个网站是谜题的地方)我发现它非常特殊,并且在你自己的答案中提供了“正确的”解决方案

rowCount = dg.Rows.Count - (dg.AllowUserToAddRows? 1 : 0);

可能适用于您的特定需求,但不能用作一般建议(它似乎假装是这样),因为显然无法使用不可见行或数据源的绑定模式禁用AddNew,如下例所示:

//#define fBoundMode

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;

namespace Samples
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            var form = new Form();
            var dg = new DataGridView { Dock = DockStyle.Fill, Parent = form };
#if fBoundMode
            dg.DataSource = new BindingList<Data>(new List<Data> { new Data { Foo = "a" }, new Data { Foo = "b" } }) { AllowNew = false };
#else
            dg.Columns.Add("Foo", "Foo");
            dg.Columns.Add("Bar", "Bar");
            dg.Rows.Add("a", "a");
            dg.Rows.Add("b", "b");
            dg.Rows.Add("c", "c");
            dg.Rows[1].Visible = false;
#endif
            var status = new Label { Dock = DockStyle.Bottom, AutoSize = false, Parent = form };
            Action updateStatus = () =>
            {
                var rowCount = dg.Rows.Count - (dg.AllowUserToAddRows ? 1 : 0);
                status.Text = "Rows: " + rowCount;
            };
            dg.UserDeletedRow += (sender, e) => updateStatus();
            var timer = new Timer { Interval = 250, Enabled = true };
            timer.Tick += (sender, e) => updateStatus();
            Application.Run(form);
        }
#if fBoundMode
        class Data
        {
            public string Foo { get; set; }
            public string Bar { get; set; }
        }
#endif
    }
}

我个人认为你提到的案例不是“按设计”,而是一些技术(实施)困难的结果。就这样,我宁愿将待遇视为异常(使用特殊代码)而不是试图概括它。但这取决于你 - 我绝对不会花更多的时间在这上面。

答案 3 :(得分:0)

为了确定DataGridView中除新行外的行数,还有一种使用LINQ的解决方案。

C#:

DataGridView1.Rows.OfType<DataGridViewRow>().Where(r=>!r.IsNewRow).Count()

VB.Net

DataGridView1.Rows.OfType(Of DataGridViewRow)().Where(Function(r) Not r.IsNewRow).Count()