0

我在 Windows CE 应用程序中有此代码:

for (int i = listBoxWork.Items.Count - 1; i > -1; i--)
{
    if (listBoxWork.Items[i].ToString().IndexOf(listboxVal) != -1)
    {
        listBoxWork.Items.RemoveAt(i);
    }
}

它因“ System.Collections.ArrayList.ArrayListEnumeratorSimple.MoveNext() 处的无效操作异常而崩溃... ”

我在“常规”Windows 窗体应用程序中尝试了相同的代码,它运行良好。如果这是 Windows CE 无法以这种方式处理的事情,我如何列表框中删除项目?

更新

这是有效的“VS 2013 代码”(目标框架 == .NET Framework 4.5.1,平台目标 == 任何 CPU)(列表框中的“blaINV”项已删除):

private void button44_Click(object sender, EventArgs e)
{
    String listboxVal = "blaINV";
    for (int i = listboxWork.Items.Count - 1; i >= 0; --i)
    {
        if (listboxWork.Items[i].ToString().IndexOf(listboxVal) != -1)
        {
            listboxWork.Items.RemoveAt(i);
        }
    }
}

该表单上的 using 语句(这是一个“沙盒”表单,我在其中测试各种事物):

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.OleDb;
using System.DirectoryServices.AccountManagement;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml;

“VS 2008”代码如下。

首先请注意,该项目的目标框架应该是 .NET 3.5,但“目标框架:”在项目 > 属性 > 应用程序选项卡中显示为灰色;如果我选择项目 > 更改目标平台,“当前平台:”== Windows CE)

但是,如果我转到 Project > Properties > Build 选项卡,Configuration 设置为“Active (Debug)”,Platform 设置为“Active (Any CPU)”,并且 Platform target 设置为“Any CPU”并且是唯一的选项在下拉列表中。

在设备选项卡(项目>属性>设备)上,目标设备设置为“Pocket PC 2003 SE Emulator”,但我并没有真正使用它。当我需要测试时,我只需将 .exe 复制到手持设备。

无论如何,这是代码(失败):

private void UpdateGUIAfterTableSend(String listboxVal)
{
    for (int i = listBoxWork.Items.Count - 1; i >= 0; --i)
    {
        if (listBoxWork.Items[i].ToString().IndexOf(listboxVal) != -1)
        {
            listBoxWork.Items.RemoveAt(i);
        }
    }
}

如您所见,除了工作代码中提供了要搜索的“虚假”字符串外,它是相同的。实际的列表框包含一个匹配“listboxVal”的值;然而,它不仅没有被删除,而且出现了上面提到的异常。

以下是非工作表单上唯一的 using 语句:

using System;
using System.Windows.Forms;

namespace HHS
{
    using System.Collections.Generic; // R# put this "using" here; like Don Henley in "The Last Resort," I don't know why

更新 2

我将 after-the-namespace using 移动到 above-the-namespace 只是为了看看它是否会产生任何影响。它没有。

更新 3

我在代码中添加了一个 catch 块:

try
{
    for (int i = listBoxWork.Items.Count - 1; i >= 0; --i)
    {
        if (listBoxWork.Items[i].ToString().IndexOf(listboxVal) != -1)
        {
            listBoxWork.Items.RemoveAt(i);
        }
    }
}
catch (Exception ex)
{
    MessageBox.Show(String.Format(
        "Exception in UpdateGUIAfterTableSend(). Message == {0}; InEx == {1}; StackTrace == {2}", 
            ex.Message, ex.InnerException, ex.StackTrace));
}

......但我没有看到消息框 - 之前的异常显示,并且在它被解雇时,应用程序崩溃 - 即使有一种薄薄的金属“bing”声音,我以前从未从设备中听到过这种声音。

更新 4

好的,为了深入了解这一点,我将 MessageBox.Show() 大量添加到代码中:

private void UpdateGUIAfterTableSend(String listboxVal)
{
    try
    {
        MessageBox.Show("Made it before for loop in UpdateGUIAfterTableSend()");
        for (int i = listBoxWork.Items.Count - 1; i >= 0; --i)
        {
            MessageBox.Show("Made it before if condition in UpdateGUIAfterTableSend()");
            if (listBoxWork.Items[i].ToString().IndexOf(listboxVal) != -1)
            {
                MessageBox.Show("Made it before remove line in UpdateGUIAfterTableSend()");
                listBoxWork.Items.RemoveAt(i);
            }
        }
        MessageBox.Show("Made it before listBoxMessages.Items.Add() in     
          UpdateGUIAfterTableSend()");
        listBoxMessages.Items.Add(String.Format("{0} sent at {1}", listboxVal, 
          DateTime.Now.ToLongTimeString()));
        MessageBox.Show("Made it after listBoxMessages.Items.Add() in 
           UpdateGUIAfterTableSend()");
    }
    catch (Exception ex)
    {
        MessageBox.Show(String.Format(
            "Exception in UpdateGUIAfterTableSend(). Message == {0}; InEx == {1}; StackTrace 
               == {2}", ex.Message, ex.InnerException, ex.StackTrace));
    }
}

这是这样调用的:

private void menuItemSEND_Inventories_Click(object sender, EventArgs e)
{
    SendInventories();
}

private void SendInventories()
{
    Cursor curse = Cursor.Current;
    Cursor.Current = Cursors.WaitCursor;
    try
    {
        foreach (String tblname in listBoxWork.Items)
        {
            // Ignore DSD tables
            if (tblname.IndexOf("DSD") == 0) continue;
            int siteNum = HHSDBUtils.GetSiteNumForTableName(tblname);
            String fileName = HHSUtils.GetGeneratedINVFileName(siteNum);
            String xmlData = HHSDBUtils.SaveAndGetINVDataAsXMLFromTable(tblname, fileName);
            String uri = 
                String.Format("http:100.200.400.800:1500/api/inventory/sendXML/duckbill/platypus/{0}", fileName);
            RESTUtils.SendHTTPRequestNoCredentials(uri, RESTUtils.HttpMethods.POST, xmlData, 
               "application/xml");
            HHSDBUtils.DeleteTableReference(tblname, "INV");
            HHSDBUtils.DropSQLiteTable(tblname, siteNum);
            UpdateGUIAfterTableSend(tblname);
        }
    }
    finally
    {
        Cursor.Current = curse;
    }
}

所以你可以看到,在 UpdateGUIAfterTableSend() 被调用之后什么都没有发生。这是我在选择 Send > Inventories 并触发这一系列事件之前看到的:

在此处输入图像描述

...这就是我在崩溃前看到的内容(listboxitem 删除代码实际上正在工作,我现在可以看到):

在此处输入图像描述

在关闭最后一个“成功”的 MessageBox.Show() 时,它会崩溃,如前所述。为什么?!?!?之后就没有其他事情发生了!?!

更新 5

所以我在方法(SendInventories())中添加了一个 catch 块,这实际上是罪魁祸首:

catch (Exception ex)
{
    MessageBox.Show(String.Format(
        "Exception in SendInventories(); Message == {0}, InEx == {1}, StackTrace == {2}", 
            ex.Message, ex.InnerException, ex.StackTrace));
}  

...我看到了这个:

在此处输入图像描述

但是,通过以这种方式捕获异常,应用程序不会崩溃。而且似乎无害——我想要完成的事情已经完成了。所以,虽然肯定对这个例外的来龙去脉感到好奇(没有双关语),但也许我现在就压制/吞下它......

更新 6

因此,如果我将 catch 块更改为:

catch (Exception ex)
{
    if (!ex.Message.Contains("InvalidOperationException"))
    {
        MessageBox.Show(String.Format(
            "Exception in SendInventories(); Message == {0}, InEx == {1}, StackTrace == {2}",
                ex.Message, ex.InnerException, ex.StackTrace));
    }
}            

...它工作得很好(我没有看到任何例外,并且两个列表框都按预期更新)。我想我会把它归结为古怪的 Windows CE 世界的变幻莫测。

4

1 回答 1

2

此代码失败,因为 for 循环已将列表框中的总项目保存为 10。
然后,您是邪恶的,通过取一个项目,让列表框继续循环直到 10,而实际上,您的列表框项目仅计数 9(您删除了一个刚刚的项目)。

一种方法是使用:

if (listBoxWork.Items.Contains(listboxVal)
{
    只获取索引;
    从 listBoxWork 中删除它;
}


更新
在您的 for 循环中,您可以在删除项目后设置 index = index - 1 。
Visual Studio 2008 仍然很原始,你不能指望它表现得像 VS 2013。

干杯,

于 2014-11-06T04:31:12.063 回答