这是一个持续存在的问题;在下面的代码中,旧代码(也失败了)被注释掉了。不过,新代码的行为方式相同:
private void UpdateGUIAfterTableSend(String listboxVal)
{
ExceptionLoggingService.Instance.WriteLog("Reached frmMain.UpdateGUIAfterTableSend");
try
{
//listBoxWork.DataSource = null; // <= This (at one time, anyway) seemed necessary to circumvent "Value does not fall within the expected range"
//// Failing ignominiously; question at https://stackoverflow.com/questions/28439941/why-is-this-array-list-removal-code-failing
//for (int i = listBoxWork.Items.Count - 1; i >= 0; --i) // try a foreach instead?
//{
// if (listBoxWork.Items[i].ToString().Contains(listboxVal))
// {
// listBoxWork.Items.RemoveAt(i);
// }
//}
BindingSource bs = listBoxWork.DataSource as BindingSource;
ExceptionLoggingService.Instance.WriteLog("Reached frmMain.UpdateGUIAfterTableSend#2");
for (int i = bs.Count - 1; i >= 0; --i)
{
if (bs[i].ToString().Contains(listboxVal))
{
bs.RemoveAt(i);
ExceptionLoggingService.Instance.WriteLog("Reached frmMain.UpdateGUIAfterTableSend#3");
}
}
}
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));
}
}
似乎第二次通过for循环,应用程序突然崩溃。我这样说是因为日志文件显示&#34;到达frmMain.UpdateGUIAfterTableSend#3&#34;但不是来自catch块的log msg。因此它必须在四个循环的第二次迭代中崩溃(在&#34;之前达到frmMain.UpdateGUIAfterTableSend#3&#34;再次记录)。因此,一旦它崩溃了它的晚安,艾琳:它崩溃如此艰难和快速,它甚至没有记录捕获块的日志消息。还是有其他解释吗?
但更重要的是:为什么第二次检查&#34;包含&#34;或者第二个要删除的地址(不应该在我的测试用例中,列表框只有一个项目)引爆代码消失的核设备吗?
这是崩溃后的最后一个日志文件:
Date: 2/11/2015 12:45:34 PM
Message: Reached frmMain.UpdateGUIAfterTableSend
Date: 2/11/2015 12:45:34 PM
Message: Reached frmMain.UpdateGUIAfterTableSend#2
Date: 2/11/2015 12:45:34 PM
Message: Reached frmMain.UpdateGUIAfterTableSend#3
Date: 2/11/2015 12:45:34 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()
我在&#34; RemoveAt&#34;之前添加了另一个日志消息。线,并得到我期待的:
Date: 2/11/2015 1:36:53 PM
Message: About to remove listbox value DSD_3_20150209151047000 at index 0
......但在此之后它会立即崩溃,所以Rake36必须是正确的。
我有点相信这会起作用:
private void UpdateGUIAfterTableSend(String listboxVal)
{
ExceptionLoggingService.Instance.WriteLog("Reached frmMain.UpdateGUIAfterTableSend");
try
{
ExceptionLoggingService.Instance.WriteLog(String.Format("About to remove listbox value {0}", listboxVal));
listBoxWork.Items.RemoveAt(listBoxWork.Items.IndexOf(listboxVal));
}
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));
}
}
......但是当我听到告诉人的声音时,我的希望破灭了!&#34; bong!&#34;然后在日志文件中搜索它:
Message: About to remove listbox value DSD_3_20150209151047000
Date: 2/11/2015 1:58:18 PM
Message: From frmMain.UpdateGUIAfterTableSend: Specified argument was out of the range of valid values.; Inner Ex: ; Stack Trace: at System.Collections.ArrayList.RemoveAt(Int32 index)
at System.Windows.Forms.ListBox.ObjectCollection.RemoveAt(Int32 index)
at HHS.frmMain.UpdateGUIAfterTableSend(String listboxVal)
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()
Date: 2/11/2015 1:58:19 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()
我甚至在&#34; RemoveAt&#34;之前添加了这个。行:
listBoxWork.DataSource = null;
......但没有任何区别。
这个(受到Ravi M Patel的启发)也崩溃了:
private void UpdateGUIAfterTableSend(String listboxVal)
{
ExceptionLoggingService.Instance.WriteLog("Reached frmMain.UpdateGUIAfterTableSend");
try
{
BindingSource bs = new BindingSource();
bs.DataSource = listBoxWork.DataSource;
for (int i = bs.Count - 1; i >= 0; i--)
{
if (bs[i].ToString().Contains(listboxVal))
{
ExceptionLoggingService.Instance.WriteLog(String.Format("About to remove listbox value {0} at index {1}", listboxVal, i));
bs.RemoveAt(i);
ExceptionLoggingService.Instance.WriteLog("Reached frmMain.UpdateGUIAfterTableSend#3");
}
}
}
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/11/2015 2:09:59 PM
Message: About to remove listbox value DSD_3_20150209151047000 at index 0
Date: 2/11/2015 2:09:59 PM
Message: Reached frmMain.UpdateGUIAfterTableSend#3
Date: 2/11/2015 2:09:59 PM
Message: From application-wide exception handler: System.InvalidOperationException: InvalidOperationException
at System.Collections.ArrayList.ArrayListEnumeratorSimple.MoveNext()
at HHS.frmMain.SendDeliveries()
有关实际修复的信息,请参阅How can I remove more than one item from a listbox?
答案 0 :(得分:2)
异常来自与你所展示的逻辑完全不同的地方。它是触发的应用程序范围的异常处理程序,而不是将创建跟踪“From frmMain.UpdateGUIAfterTableSend”的异常处理程序。异常很可能是因为绑定具有副作用。看一下bindingsource和你附加的事件。 还要在删除后添加跟踪,以便您可以看到删除实际发生或使用调试器。您的更新3显示删除确实发生。
在SendDeliveries中添加更多痕迹。你的问题在那里
答案 1 :(得分:1)
在您重复迭代时,您无法销毁列表中的元素。您需要首先收集要删除的项目,然后迭代这些项目,从过程中的原始列表中删除。
有用的模式:
Items.RemoveAt(Items.IndexOf(itemToDelete))
答案 2 :(得分:1)
使用以下内容替换try {}块中的代码:
BindingSource bs = listBoxWork.DataSource as BindingSource;
List<string> values = bs.DataSource as List<string>;
values.RemoveAll(v => v.Contains(listboxVal));
bs.ResetBindings(false);
@TaW是对的。我正在猜测这个问题。从数据源中删除元素时,它也会更新ListBox。由于您要删除选定的值,因此用户界面会尝试选择下一个值而爆炸,则没有。
所以要做到这一点,你应该这样做。假设您已将列表框绑定到名为values
的arraylist。
现在,在您的方法中,从values
而不是BindingSource中删除项目。在您的情况下,如果确定列表中只有一个值。您所要做的就是values.Remove("valuetoremove");
然后重置绑定,如此。
ArrayList values = bs.DataSource as ArrayList;
values.Remove("valuetoremove");
bs.ResetBindings(false);
您可以忽略我的答案。我认为你是类型转换的数据源已经是BindingSource类型,所以你对原始语句很好。 BindingSource bs = listBoxWork.DataSource as BindingSource;
我不知道,因为我们无法在此处查看完整的代码。
如果你想从绑定源中获得正确的行为。你最好用这种方式。
BindingSource bs = new BindingSource();
bs.DataSource = listBoxWork.DataSource;
尝试使用原始代码。
答案 3 :(得分:0)
如果你能做到这一点:
List<string> list = (List<string>) listBoxWork.DataSource;
你应该能够做到这一点:
for (int i = 0; i < list.Count; i++)
{
if (list[i].Contains(listboxVal))
{
list.RemoveAt(i);
}
}
listBox1.DataSource = null;
listBox1.Items.Clear();
listBox1.DataSource = list;
但我怀疑你的DataSource
实际上是List<string>
,因为这根本行不通。 (只显示字符串的长度!)
所以你应该修改代码以适合实际 DataSource
的类型!
如果是这样的话:
List<AString> list = new List<AString>();
这样的课程:
class AString
{
public string s { get; set; }
public AString(string s_) { s = s_; }
public override string ToString() { return s; }
}
然后这会起作用:
for (int i = list.Count - 1; i > 0; i--)
{
if (list[i].s.Contains(listboxVal))
{
list.RemoveAt(i);
}
}
listBox1.DataSource = null;
listBox1.Items.Clear();
listBox1.DataSource = list;
注意ListBox
被修改后的DataSource
doesn't automatically update。
您可以使用BindingList
:
BindingList<AString> data = new BindingList<AString>();
foreach (AStrings in list) data.Add(s);
listBox1.DataSource = data;
for (int i = data.Count - 1; i > 0; i--)
{
if (data[i].s.Contains("8"))
{
data.RemoveAt(i); // (list[i]);
}
}
现在立即反映清除..