InvalidOperationException - عند إنهاء تحرير الخلية والانتقال إلى خلية أخرى
-
23-08-2019 - |
سؤال
قمت بإجراء برنامج أردت فيه تحديث طريقة عرض شبكة البيانات يدويا. لدي طريقة لتحديث DGV عن طريق مسحها ثم إعادة إدخال البيانات. - استخدام المصمم، لقد قمت بمعالج حدث للميلزلي DGV. داخل معالج الأحداث، يتم تحديث البيانات ويتم استدعاء البيانات المنعشة مخصص DGV.
أثناء تشغيل البرنامج، كلما بدأت تحرير خلية وإنهاءه عن طريق تحديد موقع آخر، يتم طرح استثناء:
InvalidOperationException العملية غير صالحة لأنه يؤدي إلى استدعاء Reentrant إلى وظيفة SetCurrentCellAddressCore.
يصادف مصحح الأخطاء Visual C # الخط الذي يمسح البيانات: DataGridView1.rows.glear ()؛
إذا كنت ترغب في إعادة إنشاء المشكلة، فقم بإجراء مشروع Windows NOMS جديد مع Visual C #، ضع كائن DataGridView على النموذج، ولصق التعليمات البرمجية التالية للنظامي.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Error___DataGridView_Updating___Cell_endedit
{
public partial class Form1 : Form
{
// Objects
DataTable dt;
DataColumn colID;
DataColumn colName;
DataColumn colInfo;
// Constructor
public Form1()
{
InitializeComponent();
Initialize_dt();
InsertSampleData_dt();
Initialize_dataGridView1();
}
// Methods
private void Initialize_dt()
{
dt = new DataTable();
// Building Columns
// ID
colID = new DataColumn();
colID.ColumnName = "ID";
colID.DataType = typeof(int);
dt.Columns.Add(colID);
// Name
colName = new DataColumn();
colName.ColumnName = "Name";
colName.DataType = typeof(string);
dt.Columns.Add(colName);
//Info
colInfo = new DataColumn();
colInfo.ColumnName = "Info";
colInfo.DataType = typeof(string);
dt.Columns.Add(colInfo);
}
private void InsertSampleData_dt()
{
DataRow row;
// 0
row = dt.NewRow();
row["ID"] = 100;
row["Name"] = "AAAA";
row["Info"] = "First Record";
dt.Rows.Add(row);
//1
row = dt.NewRow();
row["ID"] = 101;
row["Name"] = "BBBB";
row["Info"] = "Second Record";
dt.Rows.Add(row);
//2
row = dt.NewRow();
row["ID"] = 102;
row["Name"] = "CCCC";
row["Info"] = "Third Record";
dt.Rows.Add(row);
}
private void Initialize_dataGridView1()
{
dataGridView1.AllowUserToAddRows = false;
// Data Grid Definitions
// Row Header
dataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.DisableResizing;
dataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders;
// ColumnHeaders
dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
// Building Columns
#region ID
{
DataGridViewColumn colSGID = new DataGridViewTextBoxColumn();
colSGID.Name = "ID";
colSGID.HeaderText = "#";
colSGID.ReadOnly = true;
colSGID.Visible = false;
colSGID.Resizable = DataGridViewTriState.False;
dataGridView1.Columns.Add(colSGID);
}
#endregion
#region Name
{
DataGridViewColumn colSGName = new DataGridViewTextBoxColumn();
colSGName.Name = "Name";
colSGName.HeaderText = "Name";
dataGridView1.Columns.Add(colSGName);
}
#endregion
#region Info
{
DataGridViewColumn colSGSubject = new DataGridViewTextBoxColumn();
colSGSubject.Name = "Info";
colSGSubject.HeaderText = "Description";
dataGridView1.Columns.Add(colSGSubject);
}
#endregion
Refresh_dataGridView1();
}
private void Refresh_dataGridView1()
{
int index;
dataGridView1.SuspendLayout();
dataGridView1.Rows.Clear();
//MessageBox.Show("Cleared Data. Rebuilding...");
foreach (DataRow row in dt.Rows)
{
index = dataGridView1.Rows.Add(new DataGridViewRow());
dataGridView1.Rows[index].Cells["ID"].Value = row["ID"];
dataGridView1.Rows[index].Cells["Name"].Value = row["Name"];
dataGridView1.Rows[index].Cells["Info"].Value = row["Info"];
//MessageBox.Show("row #" + index);
}
dataGridView1.ResumeLayout();
}
//Event Handlers
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
bool toUpdate = false;
int id = (int)dataGridView1.Rows[e.RowIndex].Cells["ID"].Value;
string columnName = dataGridView1.Columns[e.ColumnIndex].Name;
string value = (string)dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
if (value == null)
{
value = string.Empty;
}
switch (columnName)
{
case "Name":
if (value == string.Empty)
{
MessageBox.Show("Name Can't Be Empty!");
}
else
{
toUpdate = true;
}
break;
case "Info":
toUpdate = true;
break;
}
if (toUpdate)
{
foreach(DataRow row in dt.Rows)
{
if ( (int)row["ID"] == id)
{
row[columnName] = value;
}
}
Refresh_dataGridView1();
}
}
}
}
المحلول
هناك إجابة بواسطة Bruce.zhou في منتديات MSDN. لقد نشرت هنا مقتطف منه. هنا أيضا هو الرابط إلى المشاركة الأصلية.
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
...................................................;
if (toUpdate)
{
foreach(DataRow row in dt.Rows)
{
if ( (int)row["ID"] == id)
{
row[columnName] = value;
}
}
this.BeginInvoke(new MethodInvoker(Refresh_dataGridView1));
}
}
...
عند استخدام هذا الإصلاح، كلما تم تحديد الخلية الجديدة، يتم تحديد جميع الخلايا بينها وبين الخلية الأولى (بما في ذلك). أنا أبحث عن وسيلة لتحديد الخلية الجديدة فقط.
نصائح أخرى
طرقت رأسي على لوحة المفاتيح لمدة ساعة الماضية لحل هذه المشكلة. هنا الحل الخاص بي: النظر في المشكلة: عند تحديد خلية أخرى (أو أي عنصر تحكم داخل GridView) يتم تشغيل endedit.
قم بتطبيق الشيك التالي قبل تطبيق التعديل الخاص بك:
public void myGrid_EndEdit(object sender, DataGridViewCellEventArgs e)
{
if (!myGrid.Rows[e.RowIndex].Cells[e.ColumnIndex].Selected)
return;
//...rest of your code to apply edit below...
}
يجب أن ينطبق هذا على أي خلية يتم تحريرها. (وبالتالي لا يتم تطبيق التحرير عند فقدان التركيز؛ سوف يكفي كتابة إدخال الدخول لتطبيق التعديل)
كان عملي حوله هو التقاط حدث الرجيلي، وإذا كان الإجراء على خلية أخرى غير التي يتم تحريرها، فإنها تصدر DataGridView.dentitit (). كل شيء آخر يعمل كما هو متوقع.