Combobox SelectedItem not working propely - c#

I'm trying to retrieve the selected item from a combobox, though i can't get it to work.
Form1 form = new Form1();
string cpuCount = form.comboBox1.SelectedItem.ToString();
Now, this is not returning anything. BUT, if i insert this code in my InitializeComponent(), it selects item with index = 3, and return that proper item.
comboBox1.SelectedIndex = 3;
Why does it behave like this? If I now select for example item with index = 5, it still will think the selected item is the one with index = 3.
---------- I think i should expand to show you how my code looks.
Form1 - adding all items to the comboboxes.
public partial class Form1 : Form
{
Profile profile = new Profile();
public Form1()
{
InitializeComponent();
Profile profile = new Profile();
string[] prof = profile.getProfiles();
foreach (var item in prof)
{
comboBox5.Items.Add(Path.GetFileNameWithoutExtension(item));
}
int ram = 1024;
for (int i = 0; i < 7; i++)
{
comboBox4.Items.Add(ram + " GB");
ram = ram * 2;
}
int vram = 512;
string size;
for (int i = 0; i < 5; i++)
{
if(vram > 1000)
{
size = " GB";
}
else
{
size = " MB";
}
comboBox2.Items.Add(vram + size);
vram = vram * 2;
}
for (int i = 1; i < 5; i++)
{
comboBox1.Items.Add(i * 2);
}
for (int i = 0; i < 5; i++)
{
comboBox3.Items.Add(i * 2);
}
private void button3_Click(object sender, EventArgs e)
{
string current = profile.currentProfile();
profile.saveProfile(current);
}
}
So, button3 is my "save"button.
And here is my "Profile"-class
class Profile
{
public string folder { get; set; }
public Profile()
{
this.folder = "Profiles";
if (!File.Exists(folder))
{
Directory.CreateDirectory(folder);
File.Create(folder + "/default.cfg").Close();
}
}
public string[] getProfiles()
{
string[] files = Directory.GetFiles(folder);
return files;
}
public void saveProfile(string filename)
{
Form1 form = new Form1();
string cpuCount = "cpuCount=" + form.comboBox1.SelectedItem;
string RAM = "maxRAM=" + form.comboBox4.SelectedItem;
string VRAM = "maxVRAM=" + form.comboBox2.SelectedItem;
string threads = "cpuThreads=" + form.comboBox3.SelectedItem;
string path = folder + "/" + filename;
StreamWriter sw = new StreamWriter(path);
string[] lines = { cpuCount, RAM, VRAM, threads };
foreach (var item in lines)
{
sw.WriteLine(item);
}
sw.Close();
}
public string currentProfile()
{
Form1 form = new Form1();
string selected = form.comboBox5.SelectedValue + ".cfg".ToString();
return selected;
}
}
Thank you.

The problem is that there is nothing selected in your ComboBox. You create your form and then, without previous user interaction, you want to get the SelectedItem which is null at that moment.
When you create ComboBox control and fill it with items, SelectedItem property is null until you either programratically set it (by using for example comboBox1.SelectedIndex = 3) or by user interaction with the control. In this case you are not doing anything of the above and that is why you are geting the mentioned error.
EDIT Based on the edited question
Change your code like this:
first change the saveProfile method so you could pass the four strings which you write into the text file. Note that you could alternatively pass the reference of the form but I wouldn't suggest you that. So change the method like this:
public void saveProfile(string filename, string cpuCount, string RAM , string VRAM , string threads)
{
string path = folder + "/" + filename;
using(StreamWriter sw = new StreamWriter(path))
{
sw.WriteLine("cpuCount=" + cpuCount);
sw.WriteLine("maxRAM=" + RAM );
sw.WriteLine("maxVRAM=" + VRAM );
sw.WriteLine("cpuThreads=" + threads);
}
}
And then call it from button3 Click event handler like this:
private void button3_Click(object sender, EventArgs e)
{
string current = profile.currentProfile();
string cpuCount = this.comboBox1.SelectedItem.ToString();
string RAM = this.comboBox4.SelectedItem.ToString();
string VRAM = this.comboBox2.SelectedItem.ToString();
string threads = this.comboBox3.SelectedItem().ToString();
profile.saveProfile(current, cpuCount, RAM, VRAM, threads);
}
Or alternatively
private void button3_Click(object sender, EventArgs e)
{
string current = profile.currentProfile();
profile.saveProfile(current, this.comboBox1.SelectedItem.ToString(), this.comboBox4.SelectedItem.ToString(), this.comboBox2.SelectedItem.ToString(), this.comboBox3.SelectedItem().ToString());
}

From what I can see, you are calling form.comboBox1.SelectedItem.ToString() right after the creation of Form1. This means that the cpuCount variable is initialized right after the form is created, thus far before you have the chance to change the selected item with your mouse.
If you want to retrieve the value of the combobox after it is changed, you can use the SelectedIndexChanged event.

First of all, add a Form_Load Event and put your code in the handler. (use constructor for property initialization and other variable initialization)
private void Form1_Load(object sender, EventArgs e)
{
this.comboBox1.SelectedItem= 5; // This will set the combo box to index 5
string cpuCount = this.comboBox1.SelectedText; // This will get the text of the selected item
}
so you get the value of item at index 5 in cpuCount variable.
The selected clause gives you the values AFTER you have selected something, by default(when you run your app) there is nothing selected in the comoboBox, hence, it displays the value as null, after selecting the item you can use the combobox's selectedItem, selectedIndex, selectedText and selectedValue properties.
You can also use databinding to display items in the combobox, which in my view is a better way then adding the items manually.
to databind your combobox you can use,
// Bind your combobox to a datasource, datasource can be a from a database table, List, Dataset, etc..
IDictionary<int, string> comboDictionary = new Dictionary<int, string>();
comboDictionary.Add(1, "first");
comboDictionary.Add(2, "second");
comboDictionary.Add(3, "third");
comboBox1.DataSource = comboDictionary;
comboBox1.DisplayMember = "Key";
comboBox1.ValueMember = "Value";
//
And here now you can use combobox1.SelectedIndex to go through the item collection in the datasource :) and it will give you the value against your keys when you use combobox1.SelectedValue. Hope this helps.

Your ComoboBox doesn't have items in it. So it will not return properly. You are accessing combobox selected value rights after making form object.
And if it comboBox has items then nothing is being selected. By default nothing is selected in comboBox. You need to set it. Use this. What it returns? Set comboBox.SelectedIndex and then get selectedItem.
int selectedIndex = form.comboBox1.SelectedIndex;
Try this. Add some items in ComboBox and then get selectedItem.
Form1 form = new Form1();
form.comboBox1.Add("Item 1");
form.comboBox1.Add("Item 2");
form.comboBox1.Add("Item 3");
form.comboBox1.SelectedIndex = 1;
string cpuCount = form.comboBox1.SelectedItem.ToString();

Related

Winforms insert image into ListView / ImageList at index

Winforms, C#, VS2017
ImageList does not have an Insert method (however ListViewItemCollection does). I have tried a few different ways to insert a new image into the middle of a ListView and it's LargeImageList, but not getting it to work quite properly.
Anyone have any tried and true code that works properly?
This is what I have, but the images don't get synced properly to the items in the list.
protected void InsertThumbnail(string key, string keySelected)
{
var newImageList = new ImageList()
{
ImageSize = new Size(thumbWidth, thumbHeight)
};
var itemNew = new ListViewItem();
var foundSelected = false;
//lvAllPages.BeginUpdate();
for (int i = 0; i < lvAllPages.Items.Count; i++)
{
var item = lvAllPages.Items[i];
newImageList.Images.Add(item.Tag.ToString(), lvAllPages.LargeImageList.Images[i]);
if (item.Tag.ToString() == keySelected)
{
var image = batch.GetThumbnail(key);
newImageList.Images.Add(key, image);
itemNew = new ListViewItem()
{
BackColor = Color.Aquamarine,
ImageIndex = i,
Tag = key,
};
if (isLocal)
itemNew.Text = $"{GetFileName(key)} (insert) - {itemNew.ImageIndex}";
foundSelected = true;
}
if (foundSelected)
{
item.ImageIndex = item.ImageIndex + 1;
if (isLocal)
item.Text = $"{GetFileName(item.Tag.ToString())} - {item.ImageIndex}";
}
}
lvAllPages.LargeImageList.Dispose();
lvAllPages.LargeImageList = newImageList;
lvAllPages.Items.Insert(itemNew.ImageIndex, itemNew);
}
One more related thing, but not pertinent to the problems I am having. For anyone looking at this question and having similar issues, this helped with the issue of sorting items after inserting a new one. Default behavior when you insert a new ListViewItem at a given index, it will appear at the bottom of the list. I found this handy class to keep items sorted by index, which solved that problem:
class CompareByIndex : IComparer
{
private readonly ListView _listView;
public CompareByIndex(ListView listView)
{
this._listView = listView;
}
public int Compare(object x, object y)
{
int i = this._listView.Items.IndexOf((ListViewItem)x);
int j = this._listView.Items.IndexOf((ListViewItem)y);
return i - j;
}
}
And in the form load:
lvAllPages.ListViewItemSorter = new CompareByIndex(lvAllPages);
Obviously, that's a design decision. ImageList.Images is a ImageCollection and as such, it implements the IList interface.
Unfortunately, the Insert() method is allowed to throw a NotSupportedException. And that's what the list will do when used like a IList:
((IList)imageList.Images).Insert(5, new Bitmap(10,10));
System.NotSupportedException: 'Specified method is not supported.'
In order to have the images shown in a specific order, use the Add() method which takes the key:
imageList.Images.Add("1", new Bitmap(100,100));
That should also enable you to replace the image:
imageList.Images.RemoveByKey("1");
imageList.Images.Add("1", new Bitmap(200,200));
For that to work, you need to set the Sorting property:
listView1.Sorting = SortOrder.Ascending;
For storing additional information like path etc. use anotther data structure with the same key.
Here's the code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
ImageList imageList = new ImageList();
Dictionary<string, Metadata> metadata = new Dictionary<string, Metadata>();
private string dir = #"H:\temp";
private void button1_Click(object sender, EventArgs e)
{
// You would set this in the designer, probably
listView1.Sorting = SortOrder.Ascending;
listView1.View = View.LargeIcon;
listView1.LargeImageList = imageList;
// Make sure we start from the beginning
listView1.Items.Clear();
imageList.Images.Clear();
metadata.Clear();
// Add items
for (int i = 0; i < 10; i++)
{
var filename = "1 ("+(i+1)+").png"; // Just strange names I have
var fullFileName = Path.Combine(dir, filename);
imageList.Images.Add(i.ToString(), Bitmap.FromFile(fullFileName));
metadata.Add(i.ToString(), new Metadata{Path = fullFileName});
listView1.Items.Add(i.ToString(), "Image " + i, i.ToString());
}
// Update view
listView1.Refresh();
listView1.Invalidate();
}
private void button2_Click(object sender, EventArgs e)
{
for (int i = 3; i < 6; i++)
{
var filename = "1 ("+(i+2)+").png";
var fullFileName = Path.Combine(dir, filename);
// Change image
imageList.Images.RemoveByKey(i.ToString());
imageList.Images.Add(i.ToString(), Bitmap.FromFile(fullFileName));
// Match metadata and image
metadata[i.ToString()] = new Metadata{Path = fullFileName};
}
listView1.Refresh();
}
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count > 0)
{
var key = listView1.SelectedItems[0].ImageKey;
label1.Text = metadata[key].Path;
}
else
{
label1.Text = "No image selected";
}
}
}
internal class Metadata
{
internal string Path;
}

C# Selecting multiple results in a listbox search?

I want to search a listbox for a object value i made. This is the override string. This is how items are added into the listbox.
public override string ToString()
{
string reservatiestring;
reservatiestring ="Kamer: " + roomNumber + " Op datum: " + datum + " Aantal personen: " + personen.Count + " Naam: " + reservatienaam;
return reservatiestring;
}
I'd now like to search in my listbox for results while searching for a specific roomNumber. All the roomNumbers are saved in a combobox. This is what i have currently:
private void buttonSearch_Click(object sender, EventArgs e)
{
foreach (var item in listBox1.Items)
{
for (int i = listBox1.Items.Count - 1; i >= 0; i--)
{
if (listBox1.Items[i].ToString().ToLower().Contains(comboBox1.SelectedText.ToLower()))
{
listBox1.SetSelected(i, true);
}
else
{
MessageBox.Show("error");
}
}
This only selects one result though and its not specified to the roomNumber object only. When i put in the foreach to make it select multiple items, my program failed and i got the following error:
The list that this enumerator is bound to has been modified. An enumerator can only be used if the list is not changed
Extra info as asked for!
This is where i add the info to the listbox:
private void btnReserve_Click(object sender, EventArgs e)
{
Reservations reservatie = new Reservations();
reservatie.roomNumber = Convert.ToInt32(numericUpDownroom.Value);
reservatie.datum = dateTimePicker1.Value;
reservatie.reservatienaam = textBoxName1.Text;
for (int i = 0; i <= personcount; i++)
{
Person persoon = new Person();
persoon.naam = textBoxName1.Text;
persoon.leeftijd = Convert.ToInt32(numericUpDownAge1.Value);
reservatie.personen.Add(persoon);
}
if (!comboBox1.Items.Contains(reservatie.roomNumber))
{
comboBox1.Items.Add(reservatie.roomNumber);
}
else
reservaties.Add(reservatie);
listBox1.FormattingEnabled = false;
listBox1.Items.Add(reservatie.ToString());
The error: the error when it pops up. The dutch additional information is the initial error message.
I don't see why you need a foreach to multi select in your case especially that you are not using the "var item" anywhere in the code.
However, the exception might happen if the "SetSelected" implementation is doing some changes internally to the items.
Make sure you have configured your list for multi-select
// Set the selection mode to multiple and extended.
listBox1.SelectionMode = SelectionMode.MultiExtended;
Remove the foreach. (If you still need another loop, replace your foreach with a "for")
Check the below documentation link which has v. good example of multi-select ListBox:
https://msdn.microsoft.com/en-us/library/system.windows.forms.listbox.items(v=vs.110).aspx

Selecting and retrieving data from a class with a combo box

My current set up has a class with only 2 variables currently (string type and int amount).
I override the ToString to print both of those things together. In my form I instantiate different instances of this class and populate the combo box just fine, it prints my override.
My question is how do I determine which instance is being selected? I can use selecteditem to retrieve my tostring override fine, but what if i want to alter the amount variable of a specific instance if its selected?
SelectedItem.Instance.VariableName
I imagine it would be something like this, I'm just not familiar with that syntax.
You can add the object to the combobox and then use Display member to determine which property is shown.
https://msdn.microsoft.com/en-us/library/system.windows.forms.listcontrol.displaymember(v=vs.110).aspx
Well, that depends on how you populate the data into your ComboBox. For instance, if you use data binding, you can do something like the following:
Dictionary<string, YourClass> dict = new Dictionary<string, YourClass>();
for (int x = 0; x <= 5; x++)
{
YourClass instance = new YourClass("Test", x);
dict.Add(instance.ToString(), instance);
}
ComboBox1.DataSource = new BindingSource(dict, null);
ComboBox1.DisplayMember = "key";
ComboBox1.ValueMember = "value";
So you can easily interact with the interact with each instance based on the selected item of your ComboBox:
Console.WriteLine(((YourClass)ComboBox1.SelectedValue).amount.ToString());
Hope that helps :)
Create a List<> of your instances and set that as the DataSource() of your ComboBox. Then you can retrieve the selected item, update it somehow, then reset the DataSource causing the ComboBox to display the new values:
private List<Thing> things = new List<Thing>();
private void Form1_Load(object sender, EventArgs e)
{
Thing thing1 = new Thing();
thing1.Item = "Bob";
thing1.Value = 411;
Thing thing2 = new Thing();
thing2.Item = "Joe";
thing2.Value = -1;
things.Add(thing1);
things.Add(thing2);
comboBox1.DataSource = things;
}
private void button1_Click(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex != -1)
{
Thing thing = (Thing)comboBox1.SelectedItem;
// now do something with "thing":
thing.Value = thing.Value + 1;
// reset the ComboBox to update the entries:
comboBox1.DataSource = null;
comboBox1.DataSource = things;
comboBox1.SelectedItem = thing;
}
}
With Class Thing:
public class Thing
{
public string Item = "";
public int Value = 0;
public override string ToString()
{
return Item + ": " + Value.ToString();
}
}

Adding data to a dataGridView row in which there is already a comboboxcolumn

I have a DataGridView that is populated at runtime with a couple of ComboBoxColumn columns. For example,
var newCountryColumn = new DataGridViewComboBoxColumn();
newCountryColumn.HeaderText = "Country";
newCountryColumn.DataSource = CountryListArray.ToArray();
newCountryColumn.DisplayMember = "Name";
newCountryColumn.ValueMember = "Code";
And so on. Now, at runtime the user selects a file to open up, and it is parsed, line by line, into an array.
var lines = File.ReadAllLines(path + "\\" + choosenFile);
foreach (string line in lines) {
numOfRecords++;
errorCounter = 0;
string[] items = line.Split('\t').ToArray();
int billState = headerIndex[0] - 1;
int billCountry = headerIndex[1] - 1;
int shipState = headerIndex[2] - 1;
int shipCountry = headerIndex[3] - 1;
for (int i = 0; i < headerIndex.Count; i++) {
int index = headerIndex[i];
/*Get the state and country codes from the files using the correct indices*/
Globals.Code = items[index - 1].ToUpper();
//If the code can't be found in either list
if (!CountryList.ContainsKey(Globals.Code) && !StateList.ContainsKey(Globals.Code)) {
errorCounter++;
if (errorCounter == 1){
dataGridView1.Rows.Add(items);
}
}
}
}
Now, that works great, except for when I scroll over in the DataGridView, over to where the comboboxes are. Apparently the code doesn't like having a value from the items array being added to a pre-existing comboboxcolumn. And I get an error dialog:
The following exception occurred in the DataGridView: System.ArguementException: DataGridViewComboBoxCell value is not valid.
Can the item from the items array be shown in the combo box column?
newCountryColumn.DisplayMember = "Name";
newCountryColumn.ValueMember = "Code";
Tells newCountryColumn.DataSource to expect a collection with properties named Name and Code. But you pass it a string[]. That is wrong, which is what the error message is telling you.
There are several ways of doing this right, the most straightforward is to declare your own class with properties Name and Code:
class CountryTuple
{
public string Code { get; private set; }
public string Name { get; private set; }
public CountryTuple(string code, string name)
{
this.Code = code;
this.Name = name;
}
}
Now you can instantiate your collection:
var cts = new List<CountryTuple>();
Add instances to your collection::
cts.Add(new CountryTuple(items[index - 1].ToUpper(), whatever));
And assign it to your DataSource:
newCountryColumn.DataSource = cts;

How do I edit the name of an item in a CheckedListBox?

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.

Categories