I made a program which adds checkedListBox.Items from a text written in a TextBox . Regarding this, to make everything more esthetic , I made a rule so that if the number of Items added in CheckedListBox1 is bigger than a number I set, it will go to a second CheckedListBox and so on.
I can also save my Entries in a .txt file so I have easy access to my previous references. So naturally I also made a Load References which ,obviously, load the file I saved.
Anyhow, my dillemma is the following : When I press the Load References button it loads ALL the references (Lines) in the text into the first checkedListBox. I want it to respect the previous law. If I click Load References I want that if there are more than, lets say, 10 entries, all the other ones will go into the other checkedListBox ,by consequence, if the limit number is passed from the second checkedListBox the rest will go into the third one and so on.
I have searched StackOverflow and the Web for several solutions ,some of the more relevant ones :
First found link semi-regarding the subject
Second found link
So to not get it wrong I will state that I want to have all the entries that pass the limit be MOVED to another checkedlistBox ,not copied like the links would suggest.
This is the Line of code for my Load Reference button :
private void button8_Click(object sender, EventArgs e)
{
string fileData = File.ReadAllText(#" To-Do References .txt");
checkedListBox1.Items.AddRange(fileData.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries));
}
Also I tried several methods but this one seemed to be the closest ,even though I got almost no satisfactory result :
var i = checkedListBox1.Items.Count;
if (i >= 10)
checkedListBox2.Items.Insert(0, checkedListBox1.Items);
Regarding this line of code : It does get an entry send into the second checkedList Box it is just that the entry is called (Collection) and has nothing to do with my references.
I hope I made myself clear and thank you for support!
UPDATE
The marked answer works perfectly for this kind of program. As I have not found anything similar I believe this is most likely the best way to implement the separation of text lines into different checkedListBoxes.
if you populate listboxes properly there will be no need to move items
private void button8_Click(object sender, EventArgs e)
{
int limit = 10;
string[] fileData = File.ReadAllText(#" To-Do References .txt").Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
// this loop adds items to the 1st list until limit is reached
for(int i =0; i<limit && i<fileData.Length; i++)
checkedListBox1.Items.Add(fileData[i]);
// if there extra items, 2nd loop adds them to list №2
for(int i =limit; i<fileData.Length; i++)
checkedListBox2.Items.Add(fileData[i]);
}
Set a limit, and maybe a multiplier to control the checkedList the data will be added to.
int limit = 10;
int checkList = 1;
string[] fileData = File.ReadAllText(#" To-Do References .txt").Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < fileData.Length; i++)
{
if (i == limit * checkList)
{
checkList++;
}
switch (checkList)
{
case 1: checkedListBox1.Items.Add(fileData[i]); break;
case 2: checkedListBox2.Items.Add(fileData[i]); break;
case 3: checkedListBox3.Items.Add(fileData[i]); break;
}
}
As big as your text file gets, adding data to a checkedListBox just requires you to add a new line to the switch statement.
Well, my head is stuck in wpf land, so I would just bind it to a list of lists, in an itemscontrol, or something similar. Reading back, of course, it appears you are using winforms, so this may not be applicable...but i'll post anyways, because it can still be done this way using the WinForms DataRepeater control.
List<List<string>> mainList = new List<List<string>>();
int listIndex = 0;
string[] fileData = File.ReadAllText(#" To-Do References.txt").Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
for(int i = 0; i<=fileData.Length; i++)
{
mainList[listIndex].Add(fileData[i]);
if (i%10 == 0)
{
listIndex++;
}
}
Then bind the mainList to the control and configure your ItemTemplate.
There was lots of info on binding to the DataRepeater, but here's one link:
https://msdn.microsoft.com/en-us/library/cc488279.aspx
Related
For some reason my some of my code seems to get skipped without throwing an error.
Im writing a program for school that uses a combobox with every word in the bible that searches a bible for the word thats clicked on and outputs every verse that contains that word to a listbox.
The code that gets skipped is the forloop and output. (apperantly)
Further info:
Wordsinthebible.length = about 33000
Verses in the Bible.length = about 24000
Here is the relevant code:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//Read bible
bible = File.ReadAllText("../../LUTHER.TXT", Encoding.UTF7);
VersesInTheBible = File.ReadAllLines("../../LUTHER.TXT", Encoding.UTF7);
//"Suchwort" is just a class that saves a string(the word) and a string array(the verses)
WordsToSearch = new List<Suchwort>();
//Split bible in to words
WordsInTheBible = new List<string>(GetWords(bible).Distinct());
WordsInTheBible.Sort();
//Fill list with word and verses
for (int i = 0; i < WordsInTheBible.Count; i++)
{
WordsToSearch.Add(new Suchwort(WordsInTheBible[i], GetVerses(WordsInTheBible[i])));
}
//Give combobox Words to search by
cbx_wörter.ItemsSource = WordsToSearch;
}
public string[] GetVerses(string wort)
{
List<string> Verse = new List<string>();
for (int i = 0; i < VersesInTheBible.Length; i++)
{
if (VersesInTheBible[i].Contains(wort))
{
Verse.Add(VersesInTheBible[i]);
}
}
return Verse.ToArray();
}
Now what happens when i run the program is it doesn't crash or throw any exception but all i get is an empty combobox:
Am I looping for too long through all the words and verses or should that be OK?
but all i get is an empty combobox:
That is because the program is loading the combobox with 24,000 items on the GUI Thread and due to the huge performance hit the GUI is taking, one never seea any items.
The standard recommendation is to only do labor intensive work in a background thread/process and when done provide the item to a ViewModel property which via InotifyPropertyChange that data is ready to be shown. While the process is running alert the user to the long running process by using a WPF BusyIndicator.
Frankly no one will ever use a 24000 word drop down. It is just not feasible. I recommend you put in an edit box with a button to initiate a search. When the user pushes the button provide a managable list of items to select based on the TextBox data.
If MVVM is new check out my blog article Xaml: ViewModel Main Page Instantiation and Loading Strategy for Easier Binding to get you started.
So I want to be able to populate 1000s of thumbnails based on a list of image filepaths. I tried using the following code but I realized that after the 200+ image, my program would throw me a "A first chance exception of type 'System.OutOfMemoryException' occurred in System.Drawing.dll".
private void PopulateThumbnails(List<string> queryResults)
{
this.playerListView.Items.Clear();
this.imageList1.Images.Clear();
ImageViewer imageViewer = new ImageViewer();
foreach (string file in queryResults)
{
try
this.imageList1.Images.Add(Image.FromFile(file));
catch
Console.WriteLine("This is not an image file");
}
this.ListView.View = View.LargeIcon;
this.imageList1.ImageSize = new Size(256, 144);
this.ListView.LargeImageList = this.imageList1;
for (int j = 0; j < this.imageList1.Images.Count; j++)
{
ListViewItem item = new ListViewItem();
item.ImageIndex = j;
this.ListView.Items.Add(item);
}
}
I realize that I should probably only populate the thumbnails as needed but...
a) how do I know how many items are being loaded in the listview?
b) how do I detect scroll events in listview?
This is rather tricky.
You have two problems:
You need to know which Images you need to display
You need to make sure that you don't run out of memory or GDI resources
Unfortunately the ListView doesn't help with Events or Properties that would notify you about scrolling or tell you which items are visible.
Here is a little piece of code that will do at least the latter; it load a few thousand filenames into a list images and keep a list of 100 items, last visible:
List<string> images = new List<string>();
List<int> visibleItems = new List<int>();
void listView1_DrawItem(object sender, DrawListViewItemEventArgs e)
{
// this loads the images on demand:
if (!imageList1.Images.ContainsKey(images[e.ItemIndex]) )
{ loadImage(e.ItemIndex); e.Item.ImageIndex = imageList1.Images.Count - 1; }
// this makes sure the listView is drawn by the system
e.DrawDefault = true;
// these lines would maintain a list of items that are or were recently visible
if (!visibleItems.Contains(e.ItemIndex)) visibleItems.Add(e.ItemIndex);
if (visibleItems.Count > 1000)
{
visibleItems.Clear();
imageList1.Images.Clear();
listView1.Invalidate();
}
}
void loadImage(int index)
{
imageList1.Images.Add(images[index], new Bitmap(images[index]) );
}
You need to set the ListView.OwnerDraw = true;; then the DrawItem event will be called and after setting e.DrawDefault = true; the actual drawing will be done by the system after all.
But the event will keep telling you exactly which Items are visible.
Now you can make sure that the respective Bitmaps are loaded in your ImageList or those far away are disposed again.. so far I have only implemented a load on demand only..
Update: Like Plutonix, I have runa few test and can load 3000 Images with 128x128 pixels each with out any problems at all. I load them on demand and it seems ImageList takes care of things quite nicely: No need to dispose of the Images, GDI resources stay at a low level (<100) for my thest program. The memory foorprint keep rising while I scroll but doesn't look as if it'll be a problem. It it is I can simply do a
imageList1.Images.Clear();
..and memory drops back to the starting point. Display works fine, reloading of the list starts without a glitch.. In fact I don't use the visibleItems list any longer. I keep it in the answer, as it is a feasible way to know about these Items but atm I see no need for it..
I have a c# windows form application.I have 2 charts in my windows form. i also have a combobox and two buttons among others. What i want is according to the text of the combobox, when i press the start button to load different graphs. So at button start event according to value of combobox i call a different function that loads the charts with what i want each time. And the second button , the stop button has the code below in order to clear the charts.
chart1.Series.Clear();
chart2.Series.Clear();
Sometimes my code runs ok but there are times that it throws the error
" A chart element with the name 'kwh_price' already exists in the 'SeriesCollection'." My code for load the chart is:
string[] seriesArray = { "kwh_price", "p_cost" };
for (int i = 0; i < seriesArray.Length; i++)
{
this.chart1.Series.Add(seriesArray[i]);
this.chart1.Series[seriesArray[i]].BorderWidth = 7;
}
Am i doing something wrong??is there something more needed in order to clear the chart?? And i don't understand why sometimes it runs ok and others not.
Put the clear code in before the load code. That way you can be sure the data is cleared before adding new data.
chart1.Series.Clear();
chart2.Series.Clear();
string[] seriesArray = { "kwh_price", "p_cost" };
for (int i = 0; i < seriesArray.Length; i++)
{
this.chart1.Series.Add(seriesArray[i]);
this.chart1.Series[seriesArray[i]].BorderWidth = 7;
}
I am making a simple class extending CheckedListBox that just adds a small textbox to the right of an item when it is checked. My issue is finding a good way to place the box at the correct location.
I had initially though I could use the Controls.Find() along with the ItemCheckEventArgs index to get the coordinates of the checkbox in question, and move to the right edge of the column from there. However, that did not work, and a brief look through the CheckedListBox class seemed to show that it does not actually contain any CheckBox controls, but merely draws images of them.
I then came up with the following method:
void CreateAmountBox(int index)
{
int itemsPerCol = Height/ItemHeight;
int x = GetColumn(index, itemsPerCol)*ColumnWidth - boxWidth;
int y = (index % itemsPerCol)*ItemHeight - offset;
System.Windows.Forms.TextBox NewAmountTextBox = new System.Windows.Forms.TextBox();
NewAmountTextBox.Location = new System.Drawing.Point(x, y);
NewAmountTextBox.Name = Items[index] + "Amount";
NewAmountTextBox.Size = new System.Drawing.Size(20, boxWidth);
Controls.Add(NewAmountTextBox);
}
where GetColumn(...) returns the column of the given index (from the CheckEventArgs). This works, but it feels like a hack and is not very readable.
Two other ideas I thought of:
1) I could just create all the TextBoxes at the start, and simply hide them until they are needed. Controls like these are all created dynamically throughout the rest of the program however, and I don't want these ones to be the odd exception. It also means that some more functionality needs to be added for cases when an item is added or removed.
2) I could use mouse position, which of course won't work if the input is via keyboard. I don't anticipate it ever being so, but best not to leave that possibility.
With some googling, the only other way I found of possibly doing this was using the ListBoxItem and TranslatePoint method, but I haven't gotten that to work, and I'm unsure as to whether it even can with a CheckedListBox instead of a ListBox.
So, is there a simple way of finding the x and y of the checked item that I don't know of? Or am I limited to simply extracting the x and y declarations above into a method and leaving it there?
You can just use the GetItemRectangle function to accomplish that:
void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e) {
Rectangle r = checkedListBox1.GetItemRectangle(e.Index);
TextBox newAmountTextBox = new TextBox();
newAmountTextBox.Location = new Point(r.Left, r.Top);
//...
}
I'm simply trying to place the value from the selected cells of a datagridview into an array. I've tried it several different ways, and this one feels the most efficient, but none of the ways I've gone about have been successful. I've done plenty of searching for this fix, several results were on this site, but still no dice. Here's what I have:
Creating the array further up in the code:
public string[] addedMovies;
On clicking the Confirm button, get the number of selected cells and store that as selectedCellCount. Then, add the selected cells one at a time into the array using a while loop. Info on results below the following code:
private void btnConfirm_Click(object sender, EventArgs e)
{
int selectedCellCount = dgvFiles.GetCellCount(DataGridViewElementStates.Selected);
int i = 0;
while (i < selectedCellCount)
{
//MessageBox.Show("" + dgvFiles.SelectedRows[i].Cells[0].Value);
addedMovies[i] = dgvFiles.SelectedRows[i].Cells[0].ToString();
//addedMovies[i] = dgvFiles.SelectedRows[i].Cells[0].Value.ToString();
MessageBox.Show("" + addedMovies[i]);
i++;
}
i = 0;
}
I am successful at showing them one at a time with the commented message box line of code, and I've also tried the commented line to add the values to the array as well with no luck. However, when I select a cell or cells and click Confirm, I am greeted with: "NullReferenceException was unhandled. Object reference not set to an instance of an object." I fail to understand where there's an issue in the coding, and why I'm unable to save the values into the array.
can you try to define array like this
public string[] addedMovies = new string[100];