【问题标题】:Why is this array list removal code failing?为什么此数组列表删除代码失败?
【发布时间】:2015-02-10 19:14:49
【问题描述】:

我试图通过传递相应的文本、在列表框中查找它并删除该项目来从列表框中删除特定值。使用此代码:

private void UpdateGUIAfterTableSend(String listboxVal)
{
    ExceptionLoggingService.Instance.WriteLog("Reached frmMain.UpdateGUIAfterTableSend");
    try
    {
        listBoxWork.DataSource = null; // <= It seems necessary to set this to null to circumvent "Value does not fall within the expected range"
        for (int i = listBoxWork.Items.Count - 1; i >= 0; --i)
        {
            if (listBoxWork.Items[i].ToString().Contains(listboxVal))
            {
                listBoxWork.Items.RemoveAt(i);
            }
        }
    }
    catch (Exception ex)
    {
        String msgInnerExAndStackTrace = String.Format("{0}; Inner Ex: {1}; Stack Trace: {2}", ex.Message, ex.InnerException, ex.StackTrace);
        ExceptionLoggingService.Instance.WriteLog(String.Format("From frmMain.UpdateGUIAfterTableSend: {0}", msgInnerExAndStackTrace));
    }
}

...但是,它失败了;问题记录为:

Date: 2/10/2015 1:48:07 PM
Message: Reached frmMain.UpdateGUIAfterTableSend

Date: 2/10/2015 1:48:07 PM
Message: From application-wide exception handler: System.InvalidOperationException: InvalidOperationException
   at System.Collections.ArrayList.ArrayListEnumeratorSimple.MoveNext()
   at HHS.frmMain.SendDeliveries()
   at HHS.frmMain.menuItemSEND_Deliveries_Click(Object sender, EventArgs e)
   at System.Windows.Forms.MenuItem.OnClick(EventArgs e)
   at System.Windows.Forms.Menu.ProcessMnuProc(Control ctlThis, WM wm, Int32 wParam, Int32 lParam)
   at System.Windows.Forms.Form.WnProc(WM wm, Int32 wParam, Int32 lParam)
   at System.Windows.Forms.Control._InternalWnProc(WM wm, Int32 wParam, Int32 lParam)
   at Microsoft.AGL.Forms.EVL.EnterMainLoop(IntPtr hwnMain)
   at System.Windows.Forms.Application.Run(Form fm)
   at HHS.Program.Main()

请注意,记录异常的是“应用程序范围的异常处理程序”,而不是 UpdateGUIAfterTableSend() 中的 catch 块

列表框通过设置它的数据源来填充,如下所示:

listBoxWork.DataSource = workTables;

workTables 是由查询填充的字符串列表:

List<String> workTables = hhsdbutils.GetWorkTableNames();

我对导致问题的原因(及其解决方案)以及为什么 UpdateGUIAfterTableSend() 中的 catch 块没有记录正在引发的异常感到困惑。

更新

在史蒂夫发表评论后,我将数据源的设置取消注释为空。那么例外是:

Date: 2/10/2015 2:19:58 PM
Message: From frmMain.UpdateGUIAfterTableSend: Value does not fall within the expected range.; Inner Ex: ; Stack Trace:    at System.Windows.Forms.ListBox._VerifyNoDataSource()
   at System.Windows.Forms.ListBox.ObjectCollection.RemoveAt(Int32 index)
   at HHS.frmMain.UpdateGUIAfterTableSend(String listboxVal)

更新 2

对于阿迪·莱斯特:

private void SendDeliveries()
{
    ExceptionLoggingService .Instance.WriteLog("Reached frmMain.SendDeliveries");
    Cursor curse = Cursor.Current;
    Cursor.Current = Cursors.WaitCursor;
    try
    {
        bool firstRecord = false;
        bool lastRecord = false;
        foreach (String tblname in listBoxWork.Items)
        {
            // Ignore INV tables
            if (tblname.IndexOf("INV") == 0) continue; 
            String tblSiteNum = hhsdbutils.GetSiteNumForTableName(tblname);
            String fileName = HHSUtils.GetGeneratedDSDFileName(tblSiteNum);
            String xmlData = hhsdbutils.GetDSDDataAsXMLFromTable(tblname, fileName);
            String uri = String.Format("{0}delivery/sendXML/duckbill/platypus/{1}", HHSConsts.BASE_REST_URL, fileName);
            fileXferImp = HHSConsts.GetFileTransferMethodology();
            fileXferImp.SendDataContentsAsXML(uri, xmlData, tblname, siteNum, firstRecord, lastRecord);
            String tableRefVal = HHSUtils.GetTableRefValForTableName(tblname, "DSD");
            hhsdbutils.DeleteTableReference(tableRefVal, "DSD");
            hhsdbutils.DropTable(tblname, tblSiteNum); // <- Will actually do this only after creating replacement tables in code
            UpdateGUIAfterTableSend(tblname);
        }
    }
    finally
    {
        Cursor.Current = curse;
    }
}

【问题讨论】:

  • 异常来自SendDeliveries - 显示该方法的代码。
  • 已评论;在我这样做之前它就爆炸了(现在它又爆炸了,所以我不知道......我会再次测试它,只为 Nils Lofgrins 注释掉它)
  • 如果您将 DataSource 设置为 null,那么据我所知,ListBox 中不会有任何项目。
  • 向我们展示引发异常的代码。
  • @SriramSakthivel:不,他们还留在那里——这就是问题所在;应该删除的没有被删除。

标签: c# arraylist invalidoperationexception


【解决方案1】:

你的两种方法都是错误的。我的意思是将DataSource 设置为null,并直接从ListBox 中删除项目。

当 ListBox 是数据绑定时(即DataSource 设置),您不能直接修改Items 集合。您必须需要删除基础数据源中的项目。数据源应通知数据绑定引擎有关项目的删除,以便 ListBox 项目将同步。

为此,您的DataSource 应该支持更改通知。如果是 WPF,请使用 ObservableCollection。如果是winforms,请使用BindingList&lt;T&gt;

所以你的代码应该是这样的:

for (int i = yourDataSource.Count - 1; i >= 0; --i)
{
    if (yourDataSource[i].ToString().Contains(listboxVal))
    {
        yourDataSource.RemoveAt(i);
    }
}

【讨论】:

    【解决方案2】:

    在设置 ListBox 的 DataSource 时,使用 BindingSource 而不是直接使用 List(Of String) 这是必需的,否则绑定引擎将看不到 DataSource 中的任何更改。

    假设你想用这样的东西设置你的列表框项目,并想删除每个包含字符串“Test”的项目:

    listBoxWork = new ListBox();
    List<string> elements = new List<string>()
    {
        "Test1", "Test2", "Test3", "Example1", "Example2"
    };
    
    BindingSource bs = new BindingSource();
    bs.DataSource = elements;
    listBoxWork.DataSource = bs;
    

    现在在您尝试删除项目的代码中使用

    private void UpdateGUIAfterTableSend(String listboxVal)
    {
        ExceptionLoggingService.Instance.WriteLog("Reached frmMain.UpdateGUIAfterTableSend");
        try
        {
            BindingSource bs = listBoxWork.DataSource as BindingSource;
            for (int i = bs.Count - 1; i >= 0; --i)
            {
                if (bs[i].ToString().Contains("Test"))
                {
                    bs.RemoveAt(i);
                }
            }
        }
        catch (Exception ex)
        {
            String msgInnerExAndStackTrace = String.Format("{0}; Inner Ex: {1}; Stack Trace: {2}", ex.Message, ex.InnerException, ex.StackTrace);
            ExceptionLoggingService.Instance.WriteLog(String.Format("From frmMain.UpdateGUIAfterTableSend: {0}", msgInnerExAndStackTrace));
        }
    }
    

    【讨论】:

      【解决方案3】:

      虽然您没有提供引发异常的实际代码,但很明显您正在从正在枚举的列表中删除一个项目(可能通过 foreach)。如果集合被更改,标准集合会使任何枚举器失效。在 for 循环中删除不是问题,这就是为什么你没有在那里捕获异常的原因。似乎这个方法是在 foreach 循环内的另一个方法中调用的。

      【讨论】:

      • 我敢打赌 for 循环在 foreach 循环内。事实上,它显示在 OP 发布的附加代码中。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-02
      • 2017-09-18
      • 1970-01-01
      • 1970-01-01
      • 2018-06-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多