确定除新行外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项目
- 添加
DataGridView1
. - 在
DataGridView1
中添加2个文本列。 - 添加上述事件处理程序
- 。
- 聚焦第一列,输入
a
。 - 按Esc立即退出编辑模式。
- 查看结果。上面的处理程序打印
NewRowIndex=-1
,但它应该打印数字>= 0
。IsNewRow
的最后一个值是false
,但应该是true
。
查看MSDN: system.windows.forms.datagridview.allowusertoaddrows (仔细阅读备注部分)和MSDN论坛帖子datagridview-cancel-add-new-row
您可以使用DataGridView.AllowNew
属性作为解决方案的变通方法。
-
设置
DataGridView.AllowNew = False
这应该会删除新的插入行 -
统计DataGridView行数
DataGridView.Rows.Count
或DataGridView.RowCount
(以您的要求为准) -
再次设置
DataGridView.AllowNew = True
为添加新记录显示空白行(如果需要)
我没有测试代码片段,但这应该解决问题
编辑:
刚刚又找到两篇与你的问题相关的文章,可能对你的阅读有用:
adding-a-new-row-to-the-datagridview-programmatically-datagridviewallowusertoaddrow-false
how-to-cancel-an-add-new-by-pressing-escape
这是设计(由微软确认)。为了达到这个结果,需要进行变通计算。
没有其他事件(除了已经使用的DataGridView.UserDeletedRow
)适合计算覆盖特殊情况。在这种情况下,键值暂时不正确——参见源代码。
唯一的方法似乎是从DataGridView
和DataGridViewRow
的。net参考源中获取计算。
下面的计算假设
- 当且仅当
DataGridView.AllowUserToAddRows
为true
时,新行存在。 - 如果新行存在,它总是被定位为最后一条记录。
让我们计算:
除新行
外的行数= 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()