我得到了最奇怪的错误,我绝对无能为力。我会在这里发布一些描述以及一些代码,希望你们其中一个人可以指出我正确的方向。
我的应用程序(Winforms)允许用户将项目添加到datagridview(绑定到列表),每次添加项目时,列表都会序列化为xml文件。最初启动应用程序时,程序会检查xml文件,如果找到,则将先前添加的项添加到dgv。
我还添加了一个DataGridViewButtonColumn来删除dgv(列表)中的项目。这是一些代码。
主要课程:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new formFoldingClient());
}
表单的构造函数调用此方法初始设置dgv
private void InitialDataGridViewSetup()
{
dgvClients.DataSource = null;
//adding delete button column
DataGridViewButtonColumn btnDelete = new DataGridViewButtonColumn();
btnDelete.Name = "btnDelete";
btnDelete.Text = "Delete";
btnDelete.HeaderText = "Delete";
btnDelete.UseColumnTextForButtonValue = true;
btnDelete.DefaultCellStyle.BackColor = Color.DarkBlue;
btnDelete.DefaultCellStyle.ForeColor = Color.White;
dgvClients.Columns.Add(btnDelete);
RefreshDataGridView();
}
每次添加或删除项目时,都会通过调用此方法刷新dgv:
private void RefreshDataGridView()
{
dgvClients.DataSource = null;
if (clientList.Count != 0)
{
dgvClients.DataSource = clientList;
dgvClients.Show();
dgvClients.ClearSelection();
}
}
Method that gets triggered when Delete button on a row in the dgv is pressed, followed by the method the performs the delete
private void dgvClients_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 0) //delete button has been clicked
{
DeleteClient(dgvClients.Rows[e.RowIndex].Cells[e.ColumnIndex + 1].FormattedValue.ToString());
}
}
private void DeleteClient(string clientToDelete)
{
dgvGrid.DataSource = null;
int removeAt = new int();
for (int i=0; i<clientList.Count; i++)
{
if (clientList[i]._ClientName == clientToDelete)
{
removeAt = i;
break;
}
}
clientList.RemoveAt(removeAt);
LogToFile("Removed client: " + clientToDelete);
LogToBox("Removed client: " + clientToDelete);
RefreshDataGridView();
SaveConfigAsXml();
LogToFile("Changes after deletion persisted to clients.xml.");
}
我相信这是所有应该是必要的代码。如果您需要,请告诉我。
问题简报 当应用程序首次加载时,如果它找到xml并将这些项加载到列表中,则一切都按预期执行。我可以添加更多项目,删除所有项目(一次一个)等。
但是,如果我在没有初始xml的情况下启动,则添加项目不是问题。但是当我删除dgv中的最后一个剩余项目时,我在Main()
的最后一行得到以下异常
Index out of range Exception: {"Index -1 does not have a value."}
堆栈跟踪
at System.Windows.Forms.CurrencyManager.get_Item(Int32 index)
at System.Windows.Forms.CurrencyManager.get_Current()
at System.Windows.Forms.DataGridView.DataGridViewDataConnection.OnRowEnter(DataGridViewCellEventArgs e)
at System.Windows.Forms.DataGridView.OnRowEnter(DataGridViewCell& dataGridViewCell, Int32 columnIndex, Int32 rowIndex, Boolean canCreateNewRow, Boolean validationFailureOccurred)
at System.Windows.Forms.DataGridView.SetCurrentCellAddressCore(Int32 columnIndex, Int32 rowIndex, Boolean setAnchorCellAddress, Boolean validateCurrentCell, Boolean throughMouseClick)
at System.Windows.Forms.DataGridView.OnCellMouseDown(HitTestInfo hti, Boolean isShiftDown, Boolean isControlDown)
at System.Windows.Forms.DataGridView.OnCellMouseDown(DataGridViewCellMouseEventArgs e)
at System.Windows.Forms.DataGridView.OnMouseDown(MouseEventArgs e)
at System.Windows.Forms.Control.WmMouseDown(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.DataGridView.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at FoldingMonitorLocalClient.Program.Main() in C:\Users\xbonez\Documents\Visual Studio 2010\Projects\FoldingClient\FoldingClient\Program.cs:line 17
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
更多信息 所以,我刚才意识到如果我在dgv中有n个项目,只删除第一个项目也会导致相同的异常。删除项目2到n没有问题。
读取xml并添加到列表的代码
private void ReadFromConfigFile()
{
LogToFile("Beginning to read from clients.xml.");
XmlSerializer deserializer = new XmlSerializer(typeof(List<Client>));
try
{
List<Client> tempClientList = new List<Client>();
using (Stream reader = new FileStream("clients.xml", FileMode.Open))
{
tempClientList = ((List<Client>)deserializer.Deserialize(reader));
}
foreach (Client client in tempClientList)
{
clientList.Add(client);
}
}
catch (FileNotFoundException ex)
{
//config file does not exist
this.LogToBox("No saved settings found.");
this.LogToFile("No existing clients.xml present.", ex);
}
catch (Exception ex)
{
LogToBox("Unable to load saved settings. Please see log for more details.");
LogToFile("Failed to read clients.xml.", ex);
}
finally
{
LogToFile("Finished reading clients.xml.");
}
}
点击添加按钮时的代码
private void btnAdd_Click(object sender, EventArgs e)
{
this.tbxClientName.BackColor = Color.White;
this.tbxLogLoc.BackColor = Color.White;
bool exists = false;
foreach (Client client in clientList)
{
if (client._ClientName == this.tbxClientName.Text)
exists = true;
}
if (String.IsNullOrEmpty(tbxClientName.Text))
{
this.tbxClientName.BackColor = Color.Yellow;
LogToBox("Enter Client Name");
LogToFile("user attempted to add client without specifying client name.");
}
else if (String.IsNullOrEmpty(tbxLogLoc.Text))
{
this.tbxLogLoc.BackColor = Color.Yellow;
LogToBox("Select WorkLog location.");
LogToFile("User attempted to add client without specifying worklog location.");
}
else if (exists)
{
//client name entered by user already exists
LogToBox("Client name " + this.tbxClientName.Text + " already exists. Enter another Client name.");
LogToFile("Duplicate client name entered.");
this.tbxClientName.BackColor = Color.Yellow;
}
else
{
//everything is valid. Add new client to list
clientList.Add(new Client(tbxClientName.Text, tbxLogLoc.Text));
LogToBox("Added new client: " + tbxClientName.Text + ".");
LogToFile("Added new client: " + tbxClientName.Text + ".");
this.tbxClientName.Text = String.Empty;
this.tbxLogLoc.Text = String.Empty;
RefreshDataGridView();
SaveConfigAsXml();
}
}
答案 0 :(得分:30)
这似乎是.NET中的某种内部绑定错误。 每当使用绑定到List的DataGridView时,我都会遇到完全相同的异常。 我真的花了很多时间试图找到一个解决方案,我终于设法摆脱了这些例外 - 通过将ICurrencyManagerProvider接口添加到我的所有列表。 此接口仅具有“CurrencyManager”只读属性和“GetRelatedCurrencyManager”方法。 我只是在它们两个中都没有返回,就是这样,没有更多的CurrencyManager“索引-1没有值”的东西。
编辑:好的,刚发现“正确的方法”实际上是使用 BindingList(T)类而不是 List(of T)
答案 1 :(得分:2)
<强>更新强>
修改dgvClients_CellClick方法以包含更多检查:
if (e.ColumnIndex == 0) //delete button has been clicked
{
if (e.RowIndex >= 0)
{
DataGridViewRow dataGridViewRow = dataGridView1.Rows[e.RowIndex];
if (dataGridViewRow.Cells.Count > 1)
{
DeleteClient(dataGridViewRow.Cells[e.ColumnIndex + 1].FormattedValue.ToString());
}
}
else
{
LogToFile(e.RowIndex.ToString());
}
}
您可以修改dgvClients_CellClick
中的检查以包含e.RowIndex > 0
,以防止异常。除此之外,要了解行为的确切原因,我们必须查看添加项逻辑,也可能是clientList。
您可能需要在手动添加项目后设置所选行索引。
答案 2 :(得分:0)
在运行.NET 4.8.03752的Visual Studio 16.7.7中将列表绑定到DataGrid时,仍然存在此Microsoft Winforms错误(在单击绑定到列表的DataGrid时崩溃)。请注意,即使指定了绑定源,即使使用BindingList,ALSO下面的代码也会产生相同的错误:
var myProblems = new List<Problems>();
var bindingList = new BindingList<Problems>(myProblems);
var source = new BindingSource(bindingList, null);
myDataGrid.DataSource = source;
但是,如果我们不使用BindingSource并以这种方式直接进行操作,则不会发生该错误:
var myProblems = new BindingList<Problems>();
myDataGrid.DataSource = myProblems;
还要注意,如果要将列表绑定到DataGrid,则Class成员必须是Properties(如{get; set;}中的属性)而不是Fields(如int MyField;中的字段),因为DataGrid不会绑定到Fields ,即使已宣布公开。