DataGridView绑定问题:“索引-1没有值”。 [英] DataGridView binding problem: "Index -1 does not have a value."

查看:688
本文介绍了DataGridView绑定问题:“索引-1没有值”。的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个datagridview绑定到一个绑定源和一个表单上的几个按钮。一个按钮将一个项目添加到绑定源,另一个删除当前选定的项目。还有一个事件处理程序可以监听CurrentChanged事件,并更新删除按钮的已启用状态。

I have a datagridview bound to a binding source and a couple buttons on a form. One button adds an item to the binding source, the other removes the currently selected item. There's also an event handler that listens to the CurrentChanged event and updates the Enabled status of the Remove button.

一切都是hunky dory,直到我去从datagridview删除最后一个项目。然后我看到一个非常丑的例外:

Everything is hunky dory until I go to remove the last item from the datagridview. Then I see a very ugly exception:

   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.SetAndSelectCurrentCellAddress(Int32 columnIndex, Int32 rowIndex, Boolean setAnchorCellAddress, Boolean validateCurrentCell, Boolean throughMouseClick, Boolean clearSelection, Boolean forceCurrentCellSelection)\r\n   at System.Windows.Forms.DataGridView.MakeFirstDisplayedCellCurrentCell(Boolean includeNewRow)
   at System.Windows.Forms.DataGridView.OnEnter(EventArgs e)
   at System.Windows.Forms.Control.NotifyEnter()
   at System.Windows.Forms.ContainerControl.UpdateFocusedControl()
   at System.Windows.Forms.ContainerControl.AssignActiveControlInternal(Control value)
   at System.Windows.Forms.ContainerControl.ActivateControlInternal(Control control, Boolean originator)
   at System.Windows.Forms.ContainerControl.SetActiveControlInternal(Control value)
   at System.Windows.Forms.ContainerControl.SetActiveControl(Control ctl)
   at System.Windows.Forms.ContainerControl.set_ActiveControl(Control value)
   at System.Windows.Forms.Control.Select(Boolean directed, Boolean forward)
   at System.Windows.Forms.Control.SelectNextControl(Control ctl, Boolean forward, Boolean tabStopOnly, Boolean nested, Boolean wrap)
   at System.Windows.Forms.Control.SelectNextControlInternal(Control ctl, Boolean forward, Boolean tabStopOnly, Boolean nested, Boolean wrap)
   at System.Windows.Forms.Control.SelectNextIfFocused()
   at System.Windows.Forms.Control.set_Enabled(Boolean value)
   at Bug3324.Form1.HandleBindingSourceCurrentChanged(Object _sender, EventArgs _e) in D:\\Dev\\TempApps\\Bug3324\\Bug3324\\Form1.cs:line 41
   at System.Windows.Forms.BindingSource.OnCurrentChanged(EventArgs e)
   at System.Windows.Forms.BindingSource.CurrencyManager_CurrentChanged(Object sender, EventArgs e)
   at System.Windows.Forms.CurrencyManager.OnCurrentChanged(EventArgs e)

我在一个小的方案中解决了这个问题:

I've isolated the problem in a small scenario:

    private BindingSource m_bindingSource = new BindingSource();

    public Form1()
    {
        InitializeComponent();

        m_bindingSource.CurrentChanged += HandleBindingSourceCurrentChanged;
        m_bindingSource.DataSource = new BindingList<StringValue>();

        dataGridView1.DataSource = m_bindingSource;

        btnAdd.Click += HandleAddClick;
        btnRemove.Click += HandleRemoveClick;
    }

    private void HandleRemoveClick(object _sender, EventArgs _e)
    {
        m_bindingSource.RemoveCurrent();
    }

    private void HandleAddClick(object _sender, EventArgs _e)
    {
        m_bindingSource.Add(new StringValue("Some string"));
    }

    private void HandleBindingSourceCurrentChanged(object _sender, EventArgs _e)
    {
        // this line throws an exception when the last item is removed from
        // the datagridview
        btnRemove.Enabled = (m_bindingSource.Current != null);

    }
}

public class StringValue
{
    public string Value { get; set; }

    public StringValue(string value)
    {
        Value = value;
    }
}

通过纯实验,我发现如果我不要改变CurrentChanged事件处理程序中的按钮状态,那么一切正常。所以我怀疑某种操作顺序问题。但是什么?为什么尝试与datagridview导致问题完全无关?

Through pure experimentation, I've found that if I don't alter the button state in the CurrentChanged event handler, then everything works fine. So I suspect some sort of order of operations issue. But what? Why does attempting to make a change completely unrelated to the datagridview cause issues?

为了使事情变得更有趣,异常通常是无害的(或根本不显示)如果程序在VS中启动,并附加一个调试器。但是如果它自己执行,那么有一个消息框弹出异常详细信息。

To make things even more interesting, the exception is usually harmless (or not showing up at all) if the program is started within VS with a debugger attached. But if it's executed on its own, there's a message box popping up with exception details.

我已经尝试在datagridview上处理RowEnter事件,发现在这种情况下,它仍然认为它有一行,并尝试从绑定源检索当前项,但 m_bindingSource.Current 已经为空。为什么当CurrentChanged事件处理时这只是一个问题?

I've tried handling the RowEnter event on the datagridview and found that in this scenario, it still thinks it has a row and attempts to retrieve the Current item from the binding source, but m_bindingSource.Current is already null. Why is this only an issue when the CurrentChanged event is handled?

任何和所有的帮助将不胜感激。谢谢。

Any and all help would be greatly appreciated. Thanks.

推荐答案

我最终解决了这个问题:

I ended up resolving it like this:

private void HandleRemoveClick(object _sender, EventArgs _e)
{
    btnRemove.Enabled = false;
    m_bindingSource.RemoveCurrent();
}

private void HandleBindingSourceCurrentChanged(object _sender, EventArgs _e)
{
    if(m_bindingSource.Current != null)
        btnRemove.Enabled = true;
}

这有点奇怪,但似乎工作正常。

It's a little weird, but seems to be working fine.

这篇关于DataGridView绑定问题:“索引-1没有值”。的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆