【问题标题】:Index-1 does not have a valueIndex-1 没有值
【发布时间】:2011-06-25 08:33:39
【问题描述】:

我遇到了一个我完全不知道的最奇怪的错误。我将在此处发布描述以及一些代码,希望你们中的某个人能指出我正确的方向。

我的应用程序(Winforms)允许用户将项目添加到数据网格视图(绑定到列表),并且每次添加项目时,列表都会序列化为 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();
            }            
        }

【问题讨论】:

  • 因为,从 xml 读取项目时我没有遇到错误,但只有当用户手动添加项目时,我才会发布两个代码片段
  • 我在这里找到了很好的解释stackoverflow.com/questions/4494147/…

标签: c# winforms datagridview


【解决方案1】:

在运行 .NET 4.8.03752 的 Visual Studio 16.7.7 中将列表绑定到 DataGrid 时,此 Microsoft Winforms 错误(单击绑定到列表的 DataGrid 时崩溃)仍然存在。请注意,如果您指定绑定源,即使在使用 BindingList 时,下面的代码也会产生相同的错误:

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;

还要注意,如果您将 List 绑定到 DataGrid,则 Class 成员必须是 Properties(如 {get; set;} 而不是字段(如 int MyField;),因为 DataGrid 不会绑定到 Fields ,即使声明为 public。

【讨论】:

    【解决方案2】:

    这似乎是 .NET 中的某种内部绑定错误。 每当使用绑定到列表的 DataGridView 时,我都遇到了完全相同的异常。 我确实花了很多时间试图找到解决方案,今天我终于设法摆脱了这些异常 - 通过将 ICurrencyManagerProvider 接口添加到我的所有列表。 该接口只有一个“CurrencyManager”只读属性和一个“GetRelatedCurrencyManager”方法。 我只是在它们两个中都返回 Nothing 就是这样,不再有 CurrencyManager “索引 -1 没有价值”的东西。

    编辑:好的,刚刚发现“正确的方法”实际上是使用 BindingList(of T) 类而不是 List(of T)

    【讨论】:

    • +1 BindingList 绝对是绑定数据到DataGridView时要使用的集合
    • 如果在绑定数据List&lt;of T&gt;DataGridView之前需要将List&lt;of T&gt;转换为DataTable(通过将List&lt;of T&gt;转换为DataTable)并将其用作@,则可以解决问题987654327@。对我来说,这比转换为BindingList (of T) 更好,因为在数据绑定DataGridView.DataSource = BindingList (of T) 之后它在DataGridView 中显示1 个空行,即使BindingList (of T) 也是空的
    • +无限为BindingList(of T)
    • 使用BindingList才是真正的解决方案
    【解决方案3】:

    更新

    修改 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 &gt; 0,这应该可以防止异常。除此之外,要知道行为的确切原因,我们必须查看 add item 逻辑,并且可能也是 clientList。

    您可能必须在手动添加项目后设置选定的行索引。

    【讨论】:

    • 我会试一试您的解决方案,看看它是否有效。如果没有,我会发布更多的代码。谢谢。
    • 试过了....同样的错误。添加项目的逻辑在方法 RefreshDataGridView() 中。
    • 您确定在删除最后一项时会引发异常吗?堆栈跟踪说明了其他内容,就像在加载表单时抛出异常之类的?
    • 只有在没有从 XML 加载的情况下删除 dgv 中的第一个项目时才会出现异常。堆栈跟踪也让我失望,但表单加载完美,直到我尝试删除第一项。
    • 对 ClearSelection 的调用会删除选定的行索引,因此调用 delete 会将 RowIndex = -1 传递给您的单元格 Click 处理程序。
    猜你喜欢
    • 2019-08-12
    • 1970-01-01
    • 2019-06-29
    • 1970-01-01
    • 1970-01-01
    • 2012-07-27
    • 1970-01-01
    • 2017-10-05
    • 2017-08-27
    相关资源
    最近更新 更多