I have a page with a listing of products in a table (which is built with divs but I digress), and one column is called "Add to Shopping List" and contains a checkbox. If that checkbox is checked, then the product for that row should be placed into the user's order. On submission, the user is taken to an order review page with all the items they had selected.
The problem right now is that, even though I set the quantity of a product to "1" when the checkbox is selected, every time the form is submitted, the number of items selected for ordering is always 0.
The function that is meant to see if any items have been selected for ordering upon submission is called checkQtys:
protected bool checkQtys(ref int ItemCnt, ref ArrayList LinesToOrder)
{
Repeater locationRepeater = (Repeater)FindControl("locationRepeater");
bool validQtys = true;
string productID = "";
int qty;
qtyErrorMsg.Text = "";
qtyErrorMsgTop.Text = "";
foreach (RepeaterItem repItem in locationRepeater.Items)
{
if (repItem != null)
{
Repeater areaRepeater = (Repeater)repItem.FindControl("areaRepeater");
if (areaRepeater != null)
{
foreach (RepeaterItem skuItm in areaRepeater.Items)
{
if (skuItm != null)
{
Label SkuID = (Label)skuItm.FindControl("SkuID");
Label qtyID = (Label)skuItm.FindControl("qtyID");
PlaceHolder inner = (PlaceHolder)skuItm.FindControl("ProductTable");
if (inner != null)
{
foreach (Control ct in inner.Controls)
{
if (ct is CheckBox)
{
CheckBox lineQty = (CheckBox)ct;
Label prodID = (Label)inner.FindControl("productID");
if (lineQty.Checked)
{
productID = prodID.Text;
qty = 1;
LinesToOrder.Add(new LineItem(productID, qty));
ItemCnt++;
validQtys = true;
}
}
}
}
}
}
}
}
}
return validQtys;
}
*Note: This original was meant to check a textbox value--the "Add To Shopping List" column was originally set to take user input for specific quantities but that has been changed to the checkbox.
This is the submit function:
protected void orderSubmit(object sender, EventArgs e)
{
int ItemCnt = 0;
bool validQtys = true;
ArrayList LinesToOrder = new ArrayList();
Label lb = FindControl("order") as Label;
if (checkQtys(ref ItemCnt, ref LinesToOrder))
{
string value = checkQtys(ref ItemCnt, ref LinesToOrder).ToString();
Response.Write("value: " + value + "<br />");
if (ItemCnt == 0)
{//make sure at least one item with proper qty amount is entered before submitting the order
validQtys = false;
noItemMsg.Visible = true;
noItemMsg.Text = "<br /><br />You must order at least one item<br />";
noItemMsgTop.Visible = true;
noItemMsgTop.Text = "You must order at least one item<br />";
}
if (validQtys)
{//save the information to a session variable and send users to order review page
try
{
foreach (LineItem WorkLine in LinesToOrder)
{
lb.Text += WorkLine.SKUID + ", " + WorkLine.Qty + ";";
}
Session["orderComplete"] = lb.Text;
}
catch (Exception x)
{
Response.Write(x.Message.ToString());
}
Response.Redirect("/united-states/market/office-buildings/obproductmap/OrderReview");
}
}
}
What happens in the above function is that ItemCnt is always 0, and thus the user never can go to the order review page even if they have checked at least one of the checkboxes in the product listing table. I have no clue why this is happening--with the ref int value for ItemCnt being set in checkQtys, it should not be coming in as 0 in orderSubmit unless it is actually 0.
What am I missing?
Related
I have a datagridview named PTable which shows a table from database. I also have a button that functions to copy the data from selected rows to the textboxes I have.
This code that I have right now copies two selected rows from the datagridview but when I only select one row or when I select more than 2 rows, it says that "Index was out of range"
What should happen is that it should copy any number of rows and not only 2 rows
private void button11_Click(object sender, EventArgs e)
{
productid.Text = PTable.SelectedRows[0].Cells[0].Value + string.Empty;
productname.Text = PTable.SelectedRows[0].Cells[1].Value + string.Empty;
unitprice.Text = PTable.SelectedRows[0].Cells[4].Value + string.Empty;
productid2.Text = PTable.SelectedRows[1].Cells[0].Value + string.Empty;
productname2.Text = PTable.SelectedRows[1].Cells[1].Value + string.Empty;
unitprice2.Text = PTable.SelectedRows[1].Cells[4].Value + string.Empty;
}
If a user have not selected two rows, your index 1 (PTable.SelectedRows[1]) is not valid, because the item is not there.
Before you can run this code, you have to check, if the user selected two rows:
if (PTable.SelectedRows.Count == 2)
{
//Your code ...
}
else
{
//Not two rows selected
}
First, make sure SelectionMode of DataGridView to FullRowSelect(Hope you have done it already)
Second, Use foreach or any looping logic to go through each selected rows.
Third, It's always better to write modular code. Write a validation method which returns TRUE or FALSE based on selection of the grid rows.
Now based on returned value you need to continue writing your business logic.
Fourth, Make sure to use NULL checks
So let's start by re-factoring the code.
private void button11_Click(object sender, EventArgs e)
{
If(IsRowOrCellSelected())
{
//loop through selected rows and pick your values.
}
}
I am just writing sample, make sure PTable is accessible.
private boolean IsRowOrCellSelected()
{
if (PTable.SelectedRows.Count > 0)
{
DataGridViewRow currentRow = PTable.SelectedRows[0];
if (currentRow.Cells.Count > 0)
{
bool rowIsEmpty = true;
foreach(DataGridViewCell cell in currentRow.Cells)
{
if(cell.Value != null)
{
rowIsEmpty = false;
break;
}
}
}
if(rowIsEmpty)
return false;
else
return true;
}
Code can be still improved.
To work with varying number of selected rows I suggest the following.
My approach is:
There may be more than 5 rows, that You have to display. First create 3 panels for the TextBoxes. I have named the one for the productids as here. Generate the textboxes from code, this way it's easier to maintain more than 5 selected rows:
// This code goes to the constructor of the class. Not in the button click
List<TextBox> productids = new List<TextBox>();
List<TextBox> productnames = new List<TextBox>();
List<TextBox> unitprices = new List<TextBox>();
for (int i = 0; i < 5; i++)
{
productids.Add(new TextBox { Top = i * 32 });
productnames.Add(new TextBox { Top = i * 32 });
unitprices.Add(new TextBox { Top = i * 32 });
here.Controls.Add(productids[i]);
here2.Controls.Add(productnames[i]);
here3.Controls.Add(unitprices[i]);
}
Than You can in the button click set the value for each selected row:
// This code goes to the button click
// first empty the Textboxes:
foreach (TextBox productid in productids)
{
productid.Text = string.Empty;
}
foreach (TextBox productname in productnames)
{
productname.Text = string.Empty;
}
foreach (TextBox unitprice in unitprices)
{
unitprice.Text = string.Empty;
}
for (int i = 0; i < PTable.SelectedRows.Count; i++)
{
productids[i].Text = PTable.SelectedRows[i].Cells[0].Value.ToString();
productnames[i].Text = PTable.SelectedRows[i].Cells[1].Value.ToString();
// or better... Name the columns
// unitprices[i].Text = PTable.SelectedRows[i].Cells["unitPrices"].Value.ToString();
unitprices[i].Text = PTable.SelectedRows[i].Cells[4].Value.ToString();
}
I have a drop down list "ddlMitchelLandscape2" ,when add button triggers ,i add the selected item value in to gridview.
I am stuck here ,how to check the gridview, before add the value to grid view. The selected item is already exist in grid view or not when the add button is triggered .
Some one help me how to check the value is exist in gridview before add it to gird view please ?
protected void btnAddMitchellLandscape_Click(object sender, EventArgs e)
{
//validate to make sure Mitchell Landscape is entered
if (!ValidateMitchellPage())
return;
Assessment objAssessment = (Assessment)Session[Session_CurrentAssessment];
if (ddlMitchelLandscape2.GetSelectedItemValue > 0)
{
if (lblMitchellID.Text == string.Empty)
{
//add
AssessmentEntity objAssessmentEntity = new AssessmentEntity();
Assessment.tblMitchellLandscapeIDRow row =
objAssessment.tblMitchellLandscapeID.NewtblMitchellLandscapeIDRow();
row.MitchellLandscapeID = ddlMitchelLandscape2.GetSelectedItemValue;
row.MitchellLandscapeName = ddlMitchelLandscape2.GetSelectedItemText;
}
else
{
//Add button not visible when its not a new row
ctrlHeader.ShowError("Error: Unknown error");
return;
}
//refresh data bound table
PopulateMitchellDetailsToForm(ref objAssessment);
//clear after save
btnClearMitchellLandscape_Click(null, null);
}
}
ValidateMitchellPage()
private bool ValidateMitchellPage()
{
litMitchellError.Text = string.Empty;
if (ddlMitchelLandscape2.GetSelectedItemValue <= 0)
litMitchellError.Text = "Please select Mitchell Landscape";
if (litMitchellError.Text.Trim() == string.Empty)
{
litMitchellError.Visible = false;
return true;
}
litMitchellError.Visible = true;
return false;
}
DataBind to grid view
private void PopulateMitchellDetailsToForm(ref Assessment objAssessment)
{
Assessment.tblMitchellLandscapeIDRow[] MlData
= (Assessment.tblMitchellLandscapeIDRow[])objAssessment.tblMitchellLandscapeID.Select("SaveType <> " + Convert.ToString((int)EnumCollection.SaveType.RemoveOnly));
this.gvMitchellLandscape.DataSource = MlData;
this.gvMitchellLandscape.DataBind();
}
You have to check the selected value from the dropdown or combobox in gridview by checking each row.
You can use following code to get row of gridview.
bool isValueExist=False;
for (int i = 0; i < gridview.Rows.Count; i++)
{
String val = gridview.Rows[i].Cells[0].Value.ToString();
if(val == your_drop_down_value)
{
isValueExist=True;
break;
}
}
You have to change the cell number according to your gridview design.
I have a cascading dropdownlist inside a gridview which contains 5 columns which are ItemsType, ItemList, UnitPrice, Quantity and Total. Selecting ItemsType in 1st dropdownlist will populate items in 2nd dropdownlist i.e. ItemList which is bound to database.
Problem that I am getting is that when I click Edit button, items in 2nd dropdownlist Itemstype isn't selected though I have assigned the selectedValue.
When I ran the webform in debugging mode I saw that though value has been rightly assigned to dropdownlist.selectedvalue, it isn't accepting the value at all.
The weird thing is that when I click the edit button for the second time after 1st debug, items in dropdownlist are selected correctly.
I have used the following
ddlCarriedItems.SelectedValue = SValue;
Though SValue has values of itemlist, SelectedValue displays none.
Here's the code.
protected void btnEdit_Click(object sender, EventArgs e)
{
try
{
Button btn = (Button)sender;
GridViewRow gv = (GridViewRow)btn.NamingContainer;
string VRM_id = gv.Cells[0].Text;
dc.Company_code = Convert.ToInt32(Session["company_code"].ToString());
dc.Vrm_id = Convert.ToInt32(VRM_id);
DataTable dtVRM_CP = vrmbll.edit_VRM_carried_products(dc);
int rowIndex = 0;
if (dtVRM_CP.Rows.Count > 0)
{
for (int i = 0; i < dtVRM_CP.Rows.Count; i++)
{
DropDownList ddlItemsType = (DropDownList)gvCarriedItems.Rows[rowIndex].Cells[1].FindControl("ddlItemsType");
DropDownList ddlCarriedItems = (DropDownList)gvCarriedItems.Rows[rowIndex].Cells[2].FindControl("ddlCarriedItems");
TextBox txtItemPrice = (TextBox)gvCarriedItems.Rows[rowIndex].Cells[3].FindControl("txtItemPrice");
TextBox txtItemQty = (TextBox)gvCarriedItems.Rows[rowIndex].Cells[4].FindControl("txtItemQty");
TextBox txtItemTotal = (TextBox)gvCarriedItems.Rows[rowIndex].Cells[5].FindControl("txtItemTotal");
ddlItemsType.SelectedIndex = Convert.ToInt32((dtVRM_CP.Rows[i]["items_type"]).ToString());
int itemstype = ddlItemsType.SelectedIndex;
string SValue = dtVRM_CP.Rows[i]["items"].ToString();
if (itemstype == 1)
{
ddlCarriedItems.SelectedValue =SValue;
}
else if (itemstype == 2)
{
ddlCarriedItems.SelectedValue = SValue;
}
else if (itemstype == 3)
{
ddlCarriedItems.SelectedValue = SValue;
}
else
{ }
txtItemPrice.Text = dtVRM_CP.Rows[i]["items_price"].ToString();
txtItemQty.Text = dtVRM_CP.Rows[i]["items_qty"].ToString();
txtItemTotal.Text = dtVRM_CP.Rows[i]["items_total"].ToString();
if (i != (dtVRM_CP.Rows.Count) - 1 && gvCarriedItems.Rows.Count != (dtVRM_CP.Rows.Count))
{
AddNewRow();
}
rowIndex++;
}
}
}
catch
{ }
}
Ok I've found the problem in my code. The thing is that I had to bind dropdownlist everytime before assigning value to ddlCarriedItems.SelectedValue.
I modified my code as following as per #king.code suggestion:
if (itemstype == 1)
{
DataTable dt = vrmbll.select_raw_materials_production(dc);
ddlCarriedItems.DataSource = dt;
ddlCarriedItems.DataValueField = "ID";
ddlCarriedItems.DataTextField = "Name";
ddlCarriedItems.DataBind();
ddlCarriedItems.Items.Insert(0, new ListItem("----- Select -----", "-1"));
ddlCarriedItems.SelectedValue = SValue;
}
But I have no idea why the previous code worked when I ran debugging for 2nd time.
My gridview missing previous data when post back. Here is the scenario, when I detect insufficient stock from gvFinalised gridview, I get the category, then I get the product with highest stock and display in gvSuggested gridview.
But let's say in my gvFinalised, there are three product with three different categories is insufficient, let's say they are Noodles, Canned Food and Beverages. It was supposed to display three different products with highest stock each from different categories in gvSuggested.
However, my problem now is, it just display the last items. For example, in this scenario, Beverages. The data before Beverages just get wiped out.
Here is the code on how I detect insufficient stock:
protected void tbQuantity_TextChanged(object sender, EventArgs e)
{
tempList = new Dictionary<string, string>();
distSPUItemList = new Dictionary<string, int>();
bool valid = true;
string quantityStr = "", prodID = "";
int packagesNeeded = 0, totalUnit = 0, quantity = 0;
//Get the total packages needed for this distribution
packagesNeeded = prodPackBLL.getPackagesNeededByDistributionID(distributionID);
foreach (GridViewRow gr in gvFinalised.Rows)
{
//Clear label error message
Label lblCheckAmount = gr.FindControl("lblCheckAmount") as Label;
lblCheckAmount.Text = "";
//Get the product variant ID which set as DataKeyNames and product quantity from selected row index
prodID = gvFinalised.DataKeys[gr.RowIndex].Value.ToString();
var tbQuantity = gr.FindControl("tbQuantity") as TextBox;
if (tbQuantity != null)
{
//Check if the input is numeric
quantityStr = tbQuantity.Text;
if (!int.TryParse(quantityStr, out quantity))
{
lblCheckAmount.Text = "Non-numeric input!";
TextBox tb = (TextBox)gr.FindControl("tbQuantity") as TextBox;
}
else
{
//Add both objects into Dictionary
tempList.Add(prodID, quantityStr);
}
}
}
//Portion to check the storage level for each products stored in tempList
//Loop thru tempList. key as prod variant ID, tempList.Keys as quantity
foreach (string key in tempList.Keys)
{
//Get total unit of each products
totalUnit = prodPackBLL.getTotalProductUnit(key);
valid = true;
//Check if unitQuantity exceed storage level
if (((Convert.ToInt32(tempList[key])) * packagesNeeded) > totalUnit)
{
//Get the label control in gridview
foreach (GridViewRow gr in gvFinalised.Rows)
{
if (key == gvFinalised.DataKeys[gr.RowIndex].Value.ToString())
{
//Change the color of textBox and display the insufficient message
valid = false;
//Automatically uncheck the checkBox if invalid
TextBox tb = (TextBox)gr.FindControl("tbQuantity") as TextBox;
Label lblCheckAmount = gr.FindControl("lblCheckAmount") as Label;
lblCheckAmount.Text = "Insufficient stock!";
//Here is the place where I collect the data and display in gvSuggested
getSuggested(key);
}
}
}
else
{
if (totalUnit - ((Convert.ToInt32(tempList[key])) * packagesNeeded) == 0)
{
foreach (GridViewRow gr in gvFinalised.Rows)
{
if (key == gvFinalised.DataKeys[gr.RowIndex].Value.ToString())
{
valid = true;
Label lblCheckAmount = gr.FindControl("lblCheckAmount") as Label;
lblCheckAmount.Attributes["style"] = "color:#ffb848";
lblCheckAmount.Text = "Stock becomes 0!";
}
}
}
}
//Portion to check for valid products to be inserted into distSPUItemList
if (valid)
{
//Set the textBox color
foreach (GridViewRow gr in gvFinalised.Rows)
{
if (key == gvFinalised.DataKeys[gr.RowIndex].Value.ToString())
{
TextBox tb = (TextBox)gr.FindControl("tbQuantity") as TextBox;
}
}
//Validated items store into another list to perform Sql statement when button on click
distSPUItemList.Add(key, (Convert.ToInt32(tempList[key]) * packagesNeeded));
}
}
}
And here is the getSuggested() method to populate my gvSuggeted:
protected void getSuggested(string prodVariantID)
{
string categoryName = prodPackBLL.getCategoryByProdVariantID(prodVariantID);
//Get the list of substitute product with highest storage level sorted in descending order
List<ProductPacking> prodSubstitute = new List<ProductPacking>();
List<string> lstCategory = new List<string>();
List<string> prodIDList = new List<string>();
List<DistributionStandardPackingUnitItems> distSPUItem = new List<DistributionStandardPackingUnitItems>();
distSPUItem = this.SuggestedItems;
//Find list of substitute with highest stock level and replace the product
prodSubstitute = prodPackBLL.getProductIDWithHighestStock(categoryName);
for (int count = 0; count < prodSubstitute.Count; count++)
{
//To prevent duplication of same product and select those catories which are in current category and counting them and taking them if there are less than 1 occurrences
if (!prodIDList.Contains(prodSubstitute[count].id) && !(lstCategory.Where(x => x.Equals(categoryName)).Select(x => x).Count() >= 2))
{
prodIDList.Add(prodSubstitute[count].id);
lstCategory.Add(categoryName);
}
}
for (int j = 0; j < prodIDList.Count; j++)
{
//Get the detail of the product added into prodList and add it into distSPUItem List
distSPUItem.Add(packBLL.getSPUItemDetailByID(prodIDList[j]));
}
gvSuggested.DataSource = distSPUItem;
gvSuggested.DataBind();
this.SuggestedItems = distSPUItem;
}
private List<DistributionStandardPackingUnitItems> SuggestedItems
{
get
{
if (ViewState["SuggestedItems"] == null)
{
return new List<DistributionStandardPackingUnitItems>();
}
else
{
return (List<DistributionStandardPackingUnitItems>)ViewState["SuggestedItems"];
}
}
set
{
ViewState["SuggestedItems"] = value;
}
}
I used a viewState to store the data when postback. However, it does not work. This line in gvSuggested:
this.SuggestedItems = distSPUItem;
causing my textbox in gridView not auto post back. If I removed it, the error above appear again. Any guides? Thanks in advance.
Please enable tbQuantity text box EnableAutoPostBack = True
I have a CheckedListBox that has X number of items. These items are placed there at runtime. These items are supposed to represent reports that can be displayed in the DataGridView. What I need to do now is display the record count for each report in parenthesis right next to the report name. I tried, not for too long, to edit the actual name of the item but couldn't find out how to do it. So then, I brute forced it. Saved the items to an array, cleared the items, appended the record counts to each item in the array, created new items. Well, this has caused issues because now it's not retaining my checks and the reason why is because whenever I generate the reports, I clear the items and recreate them. Well, rather than doing another foreach loop to save the checked status, does anyone know of a way to change the text of existing items in a CheckedListBox?
Here is the code I currently have:
In the MainForm.Designer.cs:
this.clbReports.Items.AddRange(new object[] {
"Report 1",
"Report 2",
"Report 3",
"Report 4",
"Report 5",
"Report 6",
"Report 7",
"Report 8",
"Report 9",
"Report 10",
"Report 11"});
And it looks like:
And I want it to look like (but there won't all be 0's):
Here is the SelectedIndexChanged function:
private void clbReports_SelectedIndexChanged(object sender, EventArgs e)
{
string strCheckBox = clbReports.SelectedItem.ToString();
bool bShowAllIsChecked = clbReports.GetItemChecked(clbReports.FindString("Show All Error Reports"));
bool bSelected = clbReports.GetItemChecked(clbReports.FindString(strCheckBox));
int nIndex = -1;
if (strCheckBox.Contains("Show All Error Reports"))
{
foreach (string str in _strReports)
{
if (!str.Contains("Show All Error Reports") && !str.Contains("Show Tagged Records"))
{
nIndex = clbReports.FindString(str);
if (nIndex > -1)
{
clbReports.SetItemChecked(nIndex, bSelected);
}
}
}
}
else
{
if (strCheckBox.Contains("Show All Error Reports") || bShowAllIsChecked)
{
foreach (string str in _strReports)
{
nIndex = clbReports.FindString(str);
if (nIndex > -1)
{
clbReports.SetItemChecked(nIndex, false);
}
}
}
nIndex = clbReports.FindString(strCheckBox);
if (nIndex > -1)
{
clbReports.SetItemChecked(nIndex, bShowAllIsChecked ? true : bSelected);
}
}
string[] strCheckedItems = new string[clbReports.CheckedItems.Count];
clbReports.CheckedItems.CopyTo(strCheckedItems, 0);
List<string> checkBoxReportFilter = new List<string>();
foreach (ReportRecord obj in this._lstReportRecords)
{
foreach (string str in strCheckedItems)
{
if (str.Contains(obj.Description))
{
checkBoxReportFilter.Add(obj.PartID.ToString());
}
}
}
try
{
if (checkBoxReportFilter.Count == 0 && clbReports.CheckedItems.Count > 0)
{
throw new NullReferenceException();
}
_strReportFilter = String.Join(",", checkBoxReportFilter.ToArray());
}
catch (NullReferenceException)
{
_strReportFilter = "-1";
}
generateReport();
}
And here is the code where I am clearing the items, getting the report counts and creating the new items.
_lstReportRecords = _dataController.ReportList;
bool[] bChecked = new bool[clbReports.Items.Count];
int nCounter = 0;
foreach (string str in _strReports)
{
foreach (string str2 in clbReports.SelectedItems)
{
bChecked[nCounter] = str2.Contains(str);
}
nCounter++;
}
clbReports.Items.Clear();
nCounter = 0;
foreach (string str in _strReports)
{
int nCount = _lstReportRecords.Where<ReportRecord>(delegate(ReportRecord rr) {
return rr.Description == str;
}).Count();
string newReport = str + " (" + nCount + ")";
clbReports.Items.Add(newReport);
clbReports.SetItemChecked(nCounter, bChecked[nCounter]);
nCounter++;
}
Please tell me there is an easier way to do this. I tried doing foreach loops through the clbReports.Items but it wants me to cast it to a string (errored on me when trying to cast to a CheckBox) so I couldn't change the value. And even if I could cast it to a CheckBox, I have a feeling it will give me the error that Enumeration has failed because the list has been changed (or however they word it). Any and all help is welcome. Thanks.
Edit: Please know that the Report X are just so that the actual report names aren't displayed to keep it generic. However, in the code, I just copied and pasted so the Show All Error Reports and Show All Tagged Records are reports I need to check.
The right ( == most simple and most direct) answer and solution is:
this.clbReports.Items[nIndex] = "new text of the item"
yes, those items are of type "object". No, nobody minds that, string is an object too ;)
If I were you, I'd try to give the INotifyPropertyChanged Interface a go.
You Shouldn't mess with events unless necessary. this will mean you can't use the designer to create the items, but as far as I've understood, it's a runtime-modified list anyway...
In detail:
• Create A Class (e.g.'Foo') that Implements INotifyPropertyChanged (Basically this will tell any listener that the text property has changed). This class will hold the names of all entries.
• create an ObservableCollection and bind your CheckedListBox to that Collection. In WinForms you will have to create a DataBindingSource and plug your Collection to one end and the ComboBox to the other end.
• Any change made to the collection will be visible in the control.
HTH
Sebi
In order to change the items in a ListBox (or a CheckedListBox), you should change these items' ToString() result.
The easiest solution would be to create a "Holder" class, which has a reference to the report it represents. Then the Holder class' ToString() method should be something like this:
public override string ToString()
{
return String.Format("{0} ({1})", BaseStr, MyReport.RecordCount);
}
If you change MyReport.RecordCount somehow (because a report's record count changes), you can just call clbReports.Refresh(), and it'll automatically show the new value.
I think this way you don't even need the temporary array solution in the second code block; however, I'd like to suggest an alternative way of getting the item's checked state.
You can iterate through the clbReports.CheckedIndices, and fill your bChecked array with true values only for indices in that array.
Well, due to time constraints I tried something else. I went with a ListView where CheckBoxes = true and View = List. I also removed Show All Error Reports and Show Tagged Records to checkboxes outside of the list. This made it a lot easier to do the functions I wanted. Here is the new code.
MainForm.Designer.cs
//
// cbTaggedRecords
//
this.cbTaggedRecords.AutoSize = true;
this.cbTaggedRecords.Location = new System.Drawing.Point(151, 9);
this.cbTaggedRecords.Name = "cbTaggedRecords";
this.cbTaggedRecords.Size = new System.Drawing.Size(106, 17);
this.cbTaggedRecords.TabIndex = 3;
this.cbTaggedRecords.Text = "Tagged Records";
this.cbTaggedRecords.UseVisualStyleBackColor = true;
this.cbTaggedRecords.CheckedChanged += new System.EventHandler(this.ShowTaggedRecords_CheckChanged);
//
// cbAllErrorReports
//
this.cbAllErrorReports.AutoSize = true;
this.cbAllErrorReports.Location = new System.Drawing.Point(6, 9);
this.cbAllErrorReports.Name = "cbAllErrorReports";
this.cbAllErrorReports.Size = new System.Drawing.Size(102, 17);
this.cbAllErrorReports.TabIndex = 2;
this.cbAllErrorReports.Text = "All Error Reports";
this.cbAllErrorReports.UseVisualStyleBackColor = true;
this.cbAllErrorReports.CheckedChanged += new System.EventHandler(this.ShowAllErrorReports_CheckChanged);
//
// listView1
//
this.listView1.CheckBoxes = true;
listViewItem1.StateImageIndex = 0;
listViewItem2.StateImageIndex = 0;
listViewItem3.StateImageIndex = 0;
listViewItem4.StateImageIndex = 0;
listViewItem5.StateImageIndex = 0;
listViewItem6.StateImageIndex = 0;
listViewItem7.StateImageIndex = 0;
listViewItem8.StateImageIndex = 0;
listViewItem9.StateImageIndex = 0;
this.listView1.Items.AddRange(new System.Windows.Forms.ListViewItem[] {
listViewItem1,
listViewItem2,
listViewItem3,
listViewItem4,
listViewItem5,
listViewItem6,
listViewItem7,
listViewItem8,
listViewItem9});
this.listView1.Location = new System.Drawing.Point(6, 29);
this.listView1.Name = "listView1";
this.listView1.Size = new System.Drawing.Size(281, 295);
this.listView1.TabIndex = 1;
this.listView1.UseCompatibleStateImageBehavior = false;
this.listView1.View = System.Windows.Forms.View.List;
this.listView1.ItemChecked += new System.Windows.Forms.ItemCheckedEventHandler(this.listView_ItemChecked);
MainForm.cs
private void listView_ItemChecked(object sender, ItemCheckedEventArgs e)
{
if (e != null)
{
int nLength = e.Item.Text.IndexOf("(") - 1;
string strReport = nLength <= 0 ? e.Item.Text : e.Item.Text.Substring(0, nLength);
if (e.Item.Checked)
{
_lstReportFilter.Add(strReport);
}
else
{
_lstReportFilter.Remove(strReport);
}
}
List<string> checkBoxReportFilter = new List<string>();
foreach (ReportRecord obj in this._lstReportRecords)
{
foreach (string str in _lstReportFilter)
{
if (str.ToLower().Contains(obj.Description.ToLower()))
{
checkBoxReportFilter.Add(obj.PartID.ToString());
}
}
}
try
{
if (checkBoxReportFilter.Count == 0 && listView1.CheckedItems.Count > 0)
{
throw new NullReferenceException();
}
_strReportFilter = String.Join(",", checkBoxReportFilter.ToArray());
}
catch (NullReferenceException)
{
_strReportFilter = "-1";
}
if (!bShowAll)
{
generateReport();
}
}
private void ShowAllErrorReports_CheckChanged(object sender, EventArgs e)
{
bShowAll = true;
foreach (ListViewItem lvi in listView1.Items)
{
lvi.Checked = ((CheckBox)sender).Checked;
}
_lstReportFilter.Clear();
bShowAll = false;
generateReport();
}
private void ShowTaggedRecords_CheckChanged(object sender, EventArgs e)
{
bool bChecked = ((CheckBox)sender).Checked;
if (bChecked)
{
if (!_lstReportFilter.Contains("Show Tagged Records"))
{
_lstReportFilter.Add("Show Tagged Records");
}
}
else
{
_lstReportFilter.Remove("Show Tagged Records");
}
listView_ItemChecked(null, null);
}
Code to add counts to CheckBoxes
_lstReportRecords = _dataController.ReportList;
int nTotalCount = 0;
foreach (ListViewItem lvi in listView1.Items)
{
int nCount = _lstReportRecords.Where(rr => lvi.Text.Contains(rr.Description)).Count();
nTotalCount += nCount;
lvi.Text = (lvi.Text.Contains("(") ? lvi.Text.Substring(0, lvi.Text.IndexOf("(") + 1) : lvi.Text + " (") + nCount.ToString() + ")";
}
cbAllErrorReports.Text = (cbAllErrorReports.Text.Contains("(") ? cbAllErrorReports.Text.Substring(0, cbAllErrorReports.Text.IndexOf("(") + 1) : cbAllErrorReports.Text + " (") + nTotalCount.ToString() + ")";
int nTaggedCount = _lstReportRecords.Where(rr => rr.Description.Contains("Tagged")).Count();
cbTaggedRecords.Text = (cbTaggedRecords.Text.Contains("(") ? cbTaggedRecords.Text.Substring(0, cbTaggedRecords.Text.IndexOf("(") + 1) : cbTaggedRecords.Text + " (") + nTaggedCount.ToString() + ")";
Thank you all for your help and ideas.