This is really getting annoying; or, to be honest, it became quite annoying a good while back.
Programmatically removing items from a listbox should be pretty straightforward, yet it seems everything I try ends up the same: with an exception. This time it's "InvalidOperationException". In context (excerpt of log file):
Date: 2/12/2015 7:15:17 PM
Message: Reached frmMain.UpdateGUIAfterTableSend
Date: 2/12/2015 7:15:17 PM
Message: From frmMain.SendDeliveries(): InvalidOperationException; Inner Ex: ; Stack Trace: at System.Collections.ArrayList.ArrayListEnumeratorSimple.MoveNext()
at HHS.frmMain.SendDeliveries()
I populate the listbox by querying a table, and populating a list of string with the query results. I then assign that list of string as the data source of the listbox. The populating works fine; it's the de-populating that is giving me the fantods.
Here's the code. The key thing that SendDeliveries() calls, as to this problem, is UpdateGUIAfterTableSend()
private void SendDeliveries()
{
ExceptionLoggingService .Instance.WriteLog("Reached
frmMain.SendDeliveries");
Cursor curse = Cursor.Current;
Cursor.Current = Cursors.WaitCursor;
try
{
bool firstRecord = false;
bool lastRecord = false;
try
{
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);
// Verify that "delivery" is the correct val in this URL
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);
hhsdbutils.DeleteTableReference(tblname);
hhsdbutils.DropTable(tblname, tblSiteNum);
UpdateGUIAfterTableSend(tblname);
}
}
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.SendDeliveries(): {0}", msgInnerExAndStackTrace));
}
}
finally
{
Cursor.Current = curse;
}
}
private void UpdateGUIAfterTableSend(String listboxVal)
{
ExceptionLoggingService.Instance.WriteLog("Reached
frmMain.UpdateGUIAfterTableSend");
try
{
BindingSource bs = listBoxWork.DataSource as BindingSource;
List<string> values = bs.DataSource as List<string>;
values.RemoveAll(v => v.Contains(listboxVal));
bs.ResetBindings(false);
}
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("Fro
frmMain.UpdateGUIAfterTableSend: {0}", msgInnerExAndStackTrace));
}
}
Even when there are multiple items in the listbox, only one is removed, because it crashes with the InvalidOperationException. The log file indicates the exception is thrown in SendDeliveries(), but I don't grok why there's a problem.
What should happen if there are three tables being sent is:
Send the first one, and remove the listbox item that represents it to the user from the listbox
Send the second one, and remove the listbox item that represents it to the user from the listbox
Send the third one, and remove the listbox item that represents it to the user from the listbox
Yes, it seems/should be simple. Yet it will only cooperate with the first one, and then crash with that exception. Would it be less cranky if I didn't use data binding - just added the values manually, one-by-one, when populating the listbox?
UPDATE
Yes, holding the items to be removed in a list, and then removing them all at once after the fact works. I changed the code to this:
private void SendDeliveries()
{
List<String> tableNames = new List<string>();
try
{
try
{
foreach (String tblname in listBoxWork.Items)
{
String tblSiteNum
hhsdbutils.GetSiteNumForTableName(tblname);
. . .
tableNames.Add(tblname);
}
UpdateGUIAfterTableSend(tableNames);
}
. . .
private void UpdateGUIAfterTableSend(IEnumerable<String> listboxVals)
{
try
{
BindingSource bs = listBoxWork.DataSource as BindingSource;
if (bs != null)
{
List<string> values = bs.DataSource as List<string>;
foreach (String listboxVal in listboxVals)
{
if (values != null)
{
values.RemoveAll(v => v.Contains(listboxVal));
}
}
}
if (null != bs)
{
bs.ResetBindings(false);
}
}
. . .
...and it works fine now.