如何确定DataGridView 中除新行(带星号的行)之外的行数?
如果我开始输入新行然后按 Esc 取消它,则同时创建的另一个新行将消失,原始行将再次成为新行。但它不再将IsNewRow
属性设置为true
。 DataGridView.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
步骤:
DataGridView1
。DataGridView1
。a
。NewRowIndex=-1
,但它应打印数字>= 0
。上次IsNewRow
值为false
,但应为true
。答案 0 :(得分:2)
在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
以显示添加新记录的空白行(如果需要)
我没有测试过代码段,但这应该可以解决问题
修改强>
刚刚找到另外两篇与您的问题相关的文章,可能对您的阅读有用:
答案 1 :(得分:2)
除了特殊情况外,没有其他事件(已使用DataGridView.UserDeletedRow
)适合计算。在那种情况下,关键值为temporarily incorrect – see the source。
唯一的方法似乎是从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
通过调用这些方法替换标准调用后,我注意到我的项目中修复了其他几个微妙的错误,这似乎与新记录行的存在有关。
答案 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()