确定除新行外DataGridView中的行数

本文关键字:DataGridView 新行外 | 更新日期: 2023-09-27 18:16:37

我怎么能准确地确定行数在DataGridView 除了新的行(行与星号)?

如果我开始键入新行,然后通过按Esc取消它,在此期间创建的另一个新行消失,原始行再次成为新行。但是它的IsNewRow属性不再是true了。DataGridView.NewRowIndex突然被设为-1

我如何能正确地计数行除了新的行包括上述特殊情况? (NewRowIndex临时重置到-1(也影响IsNewRow)是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

步骤:

    创建WinForms VB项目
  1. 添加DataGridView1 .
  2. DataGridView1中添加2个文本列。
  3. 添加上述事件处理程序
  4. 聚焦第一列,输入a
  5. Esc立即退出编辑模式。
  6. 查看结果。上面的处理程序打印NewRowIndex=-1,但它应该打印数字>= 0IsNewRow的最后一个值是false,但应该是true

确定除新行外DataGridView中的行数

查看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为添加新记录显示空白行(如果需要)

我没有测试代码片段,但这应该解决问题

编辑:


刚刚又找到两篇与你的问题相关的文章,可能对你的阅读有用:

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

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

这是设计(由微软确认)。为了达到这个结果,需要进行变通计算。

没有其他事件(除了已经使用的DataGridView.UserDeletedRow)适合计算覆盖特殊情况。在这种情况下,键值暂时不正确——参见源代码。

唯一的方法似乎是从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)

作为vb.net扩展方法实现:

''' <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

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

你可以这样写

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
    }
}

我个人认为你提到的情况不是"设计"的,而是一些技术(实现)困难的结果。正因为如此,我宁愿把它当作例外(用特殊的代码),而不是试图概括它。但这取决于你——我绝对不会在这上面花更多的时间。

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

c#

:

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

VB。

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