When I want to add a new tab to the control I want a browser to be added to it.
Each tab/browser should have an array of string address's that the user can cycle through. Different tabs have different addresses to cycle through with left and right arrows.
I can do all this manually with one tab that uses an arraylist of addresses to navigate to but I cant do it with more than one. SO far i am able to add new tabs, and even add a browser to them but cannot navigate the browser to the address since I cannot access the browser name of the new tab. I also do not know how to assign an arraylist of string addresses dynamically. I have read in address from a text file I just dont know what to do with the arraylist.
I want to be able to make the browser of the currently selected tab navigate to the first address on the arraylist assigned to that tab. If you can point out how to do this, not even codewise but pesudo code would be helpful as I can not figure it out after spending a week trying different ways
Some snippets:
tabControl1.SelectedTab
Manual way of going forward and backwards on a tab:
private void Next()
{
if (current < list.Count-1)
{
current++;
String x = (String)list[current];
webBrowser1.Navigate(x);
addressField.Text = x;
}
else
{
Console.WriteLine("AT THE END");
}
Enabler();
}
private void Previous()
{
if (current > 0)
{
current--;
String x = (String)list[current];
webBrowser1.Navigate(x);
addressField.Text = x;
}
else
{
Console.WriteLine("AT THE START");
}
Enabler();
}
private void Enabler()
{
String x = (String)list[current];
if (current == list.Count - 1)
{
toolStripButton2.Enabled = false;
}
else
{
toolStripButton2.Enabled = true;
}
if (current == 0)
{
toolStripButton1.Enabled = false;
}
else
{
toolStripButton1.Enabled = true;
}
UpdateSeperator();
}
private void UpdateSeperator()
{
int g = list.Count;
SeperateButtons.Text = (current+1) + "/" + g;
}
Adding a tab:
private void OpenTab()
{
bookmarks.Add("http://www.beer.com");
bookmarks.Add("http://www.sky.com");
bookmarks.Add("http://www.taffatech.com");
String title = "List " + (tabControl1.TabCount + 1).ToString();
TabPage addedTabPage = new TabPage(title); //create the new tab
tabControl1.TabPages.Add(addedTabPage); //add the tab to the TabControl
WebBrowser addedWebBrowser = new WebBrowser();
addedWebBrowser.Parent = addedTabPage; //add the new webBrowser to the new tab
addedWebBrowser.Dock = DockStyle.Fill;
String add = (String) bookmarks[bookmarks.Count];
addedWebBrowser.Navigate(add);
}
Any advice would be nice, even if you do not know how to do it idea's would be great and I will try them!
Related
So, I'm trying to code simple memory game in Windows Forms but I've met a simple problem that somehow I can't pass.
This is a single button code(they all look very similar):
Match CheckForMatches = new Match();
private void Pathfinder_Click(object sender, EventArgs e)
{
CheckForMatches.AddButton(Pathfinder);
CheckForMatches.Matched();
}
(where CheckForMatches object is shared between all buttons in given form)
And here are called methods codes:
public void AddButton(Button newButton)
{
if (firstButtonPressed == null)
{
firstButtonPressed = newButton;
firstButtonPressed.ImageIndex = 0; //uncovering card
}
else
{
secondButtonPressed = newButton;
secondButtonPressed.ImageIndex = 0;
Thread.Sleep(1000);
}
}
public bool Matched()
{
if (firstButtonPressed != null && secondButtonPressed != null )
{
if (firstButtonPressed.Name != secondButtonPressed.Name)
{
if (firstButtonPressed.Text == secondButtonPressed.Text)
{
DisposeButtons();
return true;
}
else
{
NullButtons();
return false;
}
}
else
{
return false;
}
}
else
{
return false;
}
}
Now this method call one of two others, depending if last 2 clicked buttons are a pair or not(basing on their name and text):
This in case of succes disposes buttons and null Match class variables:
public void DisposeButtons()
{
firstButtonPressed.Dispose();
secondButtonPressed.Dispose();
firstButtonPressed = null;
secondButtonPressed = null;
}
This is case of failure covers cards and also nulls Match class variables:
public void NullButtons()
{
firstButtonPressed.ImageIndex = 1; //covering cards
secondButtonPressed.ImageIndex = 1;
firstButtonPressed = null;
secondButtonPressed = null;
}
The point is, no matter where I place Thread.Sleep(1000), user can never see second card he choses. He always see the first one and then, when he choses second one, either both cards are disposed(app is freezing due to that delay) or the first one becomes covered, without uncovering the second one.
EDIT:
I added output to debugger window, so now method AddButton looks like this:
public void AddButton(Button newButton)
{
if (firstButtonPressed == null)
{
firstButtonPressed = newButton;
Debug.WriteLine("Before index chaning: " + firstButtonPressed.ImageIndex);
firstButtonPressed.ImageIndex = 0; //uncovering card
Debug.WriteLine("After index chaning: " + firstButtonPressed.ImageIndex);
}
else
{
secondButtonPressed = newButton;
Debug.WriteLine("Before index chaning: " + secondButtonPressed.ImageIndex);
secondButtonPressed.ImageIndex = 0;
Debug.WriteLine("After index chaning: " + secondButtonPressed.ImageIndex);
Thread.Sleep(1000);
}
}
I can see there, that ImageIndex buttons' property actually changes between 1 and 0. However, in practice, it's only visible when first if block of this method is called. I would be grateful for answering why and how to change that.
Okay, I found out maybe not best solution, but it works. I simply forced button to refresh.
Correct form of AddButton method is:
public void AddButton(Button newButton)
{
if (firstButtonPressed == null)
{
firstButtonPressed = newButton;
Debug.WriteLine("Before index changing: " + firstButtonPressed.ImageIndex);
firstButtonPressed.ImageIndex = 0; //uncovering card
Debug.WriteLine("After index changing: " + firstButtonPressed.ImageIndex);
}
else
{
secondButtonPressed = newButton;
Debug.WriteLine("Before index changing: " + secondButtonPressed.ImageIndex);
secondButtonPressed.ImageIndex = 0;
secondButtonPressed.Refresh();
Debug.WriteLine("After index changing: " + secondButtonPressed.ImageIndex);
Thread.Sleep(500);
}
}
I hope it will be useful for someone one day.
I am facing a problem when I try to use a ListView in virtual mode with LargeIcon images.
Let say that I want to show all the graphic files contained in a array of 2000 items (the average size of each file is 2MB):
if the ListView is set to Details the display is immediate and the scroll goes up and down very smoothly;
if, instead, the ListView is set to LargeIcon the display of the visible items takes a very long time and the scroll is virtually impossible.
Waiting enough time (tens of seconds) the display is correct and the icons show the right image.
If the array contains e.g. thousands of .PDF files the display and the scroll are very quick (almost the same of the Details view) and the images show are the right PDF icons.
What I would like to get is something similar to what Windows Explorer does, i.e. show a generic icon while scrolling (fast) and then, show the right images only when the scroll stops (takes some time).
Here it is the most relevant (I think) part of the code that I am using and thanks for any help:
// Based on the example given in: https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.listview.virtualmode?view=netframework-4.8
// Notes:
// The string[] array nameFoFi contains the list of the itens to be shown in ListView1 (drives or folders [and files]).
// When I fill the array nameFoFi I also set listView1.VirtualListSize = allFoFi.Count();
// If bViewDrives = True the array nameFoFi contains only drive names.
// ...
// ...
private ListViewItem[] lwiCache; //array to cache items for the virtual list
private int firstItem; //stores the index of the first item in the cache
// ...
// ...
listView1.VirtualMode = true;
//listView1.View = View.Details;
listView1.View = View.LargeIcon;
listView1.SmallImageList = new ImageList();
listView1.SmallImageList.ColorDepth = ColorDepth.Depth32Bit;
listView1.SmallImageList.ImageSize = new System.Drawing.Size(20, 20);
listView1.LargeImageList = new ImageList();
listView1.LargeImageList.ColorDepth = ColorDepth.Depth16Bit;
listView1.LargeImageList.ImageSize = new System.Drawing.Size(50, 50);
// ...
// ...
void listView1_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
{
//check to see if the requested item is currently in the cache
if (lwiCache != null && e.ItemIndex >= firstItem && e.ItemIndex < firstItem + lwiCache.Length)
{
//A cache hit, so get the ListViewItem from the cache instead of making a new one.
e.Item = lwiCache[e.ItemIndex - firstItem];
}
else
{
//A cache miss, so create a new ListViewItem and pass it back.
string nameFoFi = allFoFi[e.ItemIndex];
e.Item = ListViewNewItem(nameFoFi);
}
}
void listView1_CacheVirtualItems(object sender, CacheVirtualItemsEventArgs e)
{
if (lwiCache != null && e.StartIndex >= firstItem && e.EndIndex <= firstItem + lwiCache.Length)
{
//If the newly requested cache is a subset of the old cache,
//no need to rebuild everything, so do nothing.
return;
}
//Now we need to rebuild the cache.
firstItem = e.StartIndex;
int length = e.EndIndex - e.StartIndex + 1; //indexes are inclusive
lwiCache = new ListViewItem[length];
lblCacheTime.Text = firstItem.ToString() + " " + length.ToString();
//Fill the cache with the appropriate ListViewItems.
for (int i = 0; i < length; i++)
{
string nameFoFi = allFoFi[i + firstItem];
lwiCache[i] = ListViewNewItem(nameFoFi);
}
}
private ListViewItem ListViewNewItem(string itemName)
{
string name;
ListViewItem lwItem;
if (bViewDrives)
{
name = itemName;
}
else
{
name = Path.GetFileName(itemName);
}
lwItem = new ListViewItem(name, 0);
lwItem.Tag = itemName;
{
if (listView1.View == View.Details)
{
lwItem.ImageIndex = GetListViewSmallIcons(itemName);
GetDetails(lwItem, itemName);
}
else
lwItem.ImageIndex = GetListViewUniIcons(itemName);
}
return lwItem;
}
// From: https://stackoverflow.com/questions/670546/determine-if-file-is-an-image
public static readonly List<string> ImageExtensions = new List<string> { ".JPG", ".JPE", ".BMP", ".GIF", ".PNG" };
private int GetListViewUniIcons(string nameFoFi)
{
int iconIndex = 0;
if (bViewDrives)
{
// Get the icon of the drive nameFoFi:
Icon iconFo = GetDriveIcon(nameFoFi, true);
listView1.SmallImageList.Images.Add(nameFoFi, iconFo.ToBitmap());
listView1.LargeImageList.Images.Add(nameFoFi, iconFo.ToBitmap());
iconIndex = listView1.SmallImageList.Images.Count - 1;
}
else if (Directory.Exists(nameFoFi))
{
// Get the icon of the folder nameFoFi:
Icon iconFo = GetFolderIcon(nameFoFi);
listView1.SmallImageList.Images.Add(nameFoFi, iconFo.ToBitmap());
listView1.LargeImageList.Images.Add(nameFoFi, iconFo.ToBitmap());
iconIndex = listView1.SmallImageList.Images.Count - 1;
}
else // IsFile:
{
if (ImageExtensions.Contains(Path.GetExtension(nameFoFi).ToUpperInvariant()) && bEndScroll)
{
// Get the image of the file nameFoFi:
Bitmap image = (Bitmap) Image.FromFile(nameFoFi); // <-- here is where most of the time is lost.
listView1.SmallImageList.Images.Add(nameFoFi, image);
listView1.LargeImageList.Images.Add(nameFoFi, image);
iconIndex = listView1.LargeImageList.Images.Count - 1;
}
else
{
// Get the icon of the file nameFoFi:
Icon iconFi = GetFileIcon(nameFoFi, Win32.IconSize.Large, false);
listView1.SmallImageList.Images.Add(iconFi.ToBitmap());
listView1.LargeImageList.Images.Add(nameFoFi, iconFi.ToBitmap());
iconIndex = listView1.SmallImageList.Images.Count - 1;
}
}
return iconIndex;
}
So I've just been making a basic little calculator made up of buttons and a textbox(tbxSum).
The problem I'm having is that if an invalid sum is input I want my catch block to pick it up(which it does) and replace what's in the textbox with the most recent result in the calculator(which it doesn't).
So say I say:
3+3=6
My calculator will now put 6 in the textbox for the next sum.
So then say I did:
6//3
It's invalid which the calculator picks up, but I want the textbox value to return to 6 from the previous sum.
This is what I've tried:
var myButton = (Button)sender;
if (myButton.Content.ToString() == "=")
{
DataTable dt = new DataTable();
string s = tbxSum.Text;
string result = "";
if (s.Contains("("))
{
s = s.Replace("(", "*(");
}
try
{
var v = dt.Compute(s, "");
tbkSum.Text = s + "=" + v.ToString();
tbxSum.Text = v.ToString();
}
catch
{
MessageBox.Show("Invalid Sum");
tbxSum.Text = result;
}
}
I also have a textblock(tbkSum) which shows the previous sum so I thought maybe I could take everything in there to the right of the equals sign but I have no idea how to do that.
class Calculate(){
private boolean lastGoodValueSet = false;
private int lastGoodValue = 0;
void buttonFunction(){
if (myButton.Content.ToString() == "=")
{
//Your code
try
{
var v = dt.Compute(s, "");
tbkSum.Text = s + "=" + v.ToString();
lastGoodValue = v;
lastGoodValueSet = true;
}
catch
{
MessageBox.Show("Invalid Sum");
tbxSum.Text = result;
if (lastGoodValueSet)
tbxSum.Text = lastGoodValue;
}
}
}
}
This is an example set of code you could use, it's a simple value that you have to store to say if a good computation has been done and if so, at the point of error we want to go back to the computation. Hope that helps! You'll want to put some kind of message to the user, so they know there was an error though.
We have to do this, as at the point of the user pressing the equals button, the value has already changed inside tbkSum, we need it before the user has changed the value, so the best time to grab it is at the point when we update the tbkSum text value at a successful calculation
This is also assuming you do not create a new instance of the Calculate class each time you do your computation. Otherwise you'd need to store the number somewhere else
EDIT
The other way to fix this issue is to instead prevent the duplicate in the first place, I read from your other comments that you control what goes into the text box by buttons on the application. Assuming all buttons go through the same method of buttonFunction() then you could do:
private char[] buttonChars = {'/','*', '+'/*e.t.c*/}
void buttonFunction(){
string buttonPressedStr = myButton.Content.ToString();
char buttonPressed = buttonPressedStr[0];
int pos = Array.IndexOf(buttonChars , buttonPressed);
if (pos > -1)
{
if (tbxSum.Text.Length > 0){
char last = tbxSum.Text[tbxSum.Text.Length - 1];
pos = Array.IndexOf(buttonChars , last);
}
else
pos = 0;
if (pos > -1){
tbkSum.Text += buttonPressedStr;
}
}
There are cleaner ways to do this, but it's an example of how you could have prevented your issue in the first place. Some explanation:
buttonChars is an array of your different button types that would be appended to your text in the box, an example is +, -, and so on
First it checks if the button pressed was in your collection of specified buttonChars
If so, we have to check what the last thing added to the tbxSum was
If the last thing added to tbxSum was again found in the buttonChars array, we don't want to append a string
Otherwise, if the tbxSum was empty or had another character at the end, we can append our character
You can store the old value in a variable declard outside the try block and use this variable in your catch block again:
string oldSumValue = tbxSum.Text;
try
{
// your code
}
catch
{
tbxSum.Text = oldSumValue ;
MessageBox.Show("Invalid Sum");
}
Alternatively I've come up with this to prevent there being:
A)Duplicate of '*' or '/'
B)Sum starting with '*' or '/'
public MainWindow()
{
InitializeComponent();
if (tbxSum.Text == "")
{
btnDiv.IsEnabled = false;
btnMult.IsEnabled = false;
}
}
protected void btnSumClick(object sender, EventArgs e)
{
btnDiv.IsEnabled = true;
btnMult.IsEnabled = true;
var myButton = (Button)sender;
int pos = tbxSum.Text.Length;
if (pos > 0)
{
if ((tbxSum.Text[pos - 1] == '/' || tbxSum.Text[pos - 1] == '*') &&
(myButton.Content.ToString() == "/" || myButton.Content.ToString() == "*"))
{
int location = tbxSum.Text.Length - 1;
tbxSum.Text = tbxSum.Text.Remove(location, 1);
}
}
}
First of all im sorry for my English. Im a beginner programmer in C# using VS Express 2013.
This is my simple problem i think:
I have a combobox (cboMantello) with two items inside.
Then i have a button that uses the attributes of the selected item and add them into my character stats.
Another button removes that attributes.
To avoid Users spam the first button i disabled it and also set my combobox.enabled to false.
At this point comes up the problem. On disabling the combobox, it returns on the first item in list, so if i select the second item and press the "equipe" buttom it adds the attributes, but then the combobox switch to the first item.So if i push the "remove" button the code remove the first item attributes.
I dont know how tell combobox to frezze on second item during the enabled = false phase.
Thanks for help, and sry again for my grammatical "horrors" !
Heres my code:
private void UpdateListaMantelliInventarioUI()
{
List<Mantello> mantelli = new List<Mantello>();
foreach (OggettoInventario oggettoInventario in _player.Inventario)
{
if (oggettoInventario.Dettagli is Mantello)
{
if (oggettoInventario.Quantità > 0)
{
mantelli.Add((Mantello)oggettoInventario.Dettagli);
}
}
}
if (mantelli.Count == 0)
{
cboMantello.Enabled = false;
}
else
{
cboMantello.DataSource = mantelli;
cboMantello.DisplayMember = "Nome";
cboMantello.ValueMember = "ID";
cboMantello.SelectedIndex = 0;
}
}
private void btMantello_Click(object sender, EventArgs e)
{
Mantello mantellocorrente = (Mantello)cboMantello.SelectedItem;
_player.DifesaMagica = (_player.DifesaMagica + mantellocorrente.AggiungeDifesaMagica);
lblVesteDifesa.Text = "(+" + mantellocorrente.AggiungeDifesaMagica.ToString() + ")";
toolTip1.SetToolTip(lblVesteDifesa, mantellocorrente.Nome.ToString());
_player.Mana = (_player.Mana + mantellocorrente.AggiungeMana);
lblVesteMana.Text = "(+" + mantellocorrente.AggiungeMana.ToString() + ")";
toolTip1.SetToolTip(lblVesteMana, mantellocorrente.Nome.ToString());
_player.Evasione = (_player.Evasione + mantellocorrente.AggiungeEvasione);
lblVesteEvasione.Text = "(+" + mantellocorrente.AggiungeEvasione.ToString() + ")";
toolTip1.SetToolTip(lblVesteEvasione, mantellocorrente.Nome.ToString());
btMantello.Enabled = false;
btTogliMantello.Enabled = true;
cboMantello.Enabled = false;
UpdatePlayerStats();
UpdateListaMantelliInventarioUI();
}
private void btTogliMantello_Click(object sender, EventArgs e)
{
Mantello mantellocorrente = (Mantello)cboMantello.SelectedItem;
if (btMantello.Enabled == false)
{
btTogliMantello.Enabled = true;
_player.DifesaMagica = (_player.DifesaMagica - mantellocorrente.AggiungeDifesaMagica);
lblVesteDifesa.Text = "";
_player.Mana = (_player.Mana - mantellocorrente.AggiungeMana);
lblVesteMana.Text = "";
_player.Evasione = (_player.Evasione - mantellocorrente.AggiungeEvasione);
lblVesteEvasione.Text = "";
UpdatePlayerStats();
btMantello.Enabled = true;
cboMantello.Enabled = true;
}
btTogliMantello.Enabled = false;
}
The reason the Combo Box is resetting is because you are changing its contents when you call UpdateListaMantelliInventarioUI() in the click event for bntMantello, specifically the lines cboMantello.DataSource = mantelli; and cboMantello.SelectedIndex = 0;.
Some options to consider:
Is it necessary to update the combo box after they click equip/unequip?
If it is, you could either add/remove from cboMantello.Items directly.
You could also get the SelectedIndex/Item from cboMantello before you update it. After you update cboMantello, you could loop through the items and update the SelectedIndex/Item.
Some code:
private void UpdateListaMantelliInventarioUI()
{
var previousSelection = cboMantello.SelectedItem;
...
else
{
...
if (cboMantello.Items.Contains(previousSelection))
cboMantello.SelectedItem = previousSelection;
else
cboMantello.SelectedIndex = 0;
}
}
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.