I have a drop down combo box that changes the image of a picture box. The images are stored in a resx file with an array that counts them, so that if I ever decide to add more, I need only to update the combo box, and add the images to the resx file. The problem I'm having is that when I update the image with the combo box, the images in the resx aren't in alphabetical order, but they do change the image on the picture box.
Here is my code
ResourceSet cardResourceSet = Properties.Resources.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true);
attributes = new Image[cardCount];
cardCount = 0;
foreach (DictionaryEntry entry in cardResourceSet)
{
string resourceKey = (string)entry.Key;
object resource = entry.Value;
cardCount++;
}
attributes = new Image[cardCount];
cardCount = 0;
foreach (DictionaryEntry entry in cardResourceSet)
{
attributes[cardCount] = (Image)entry.Value;
cardCount++;
}
if (attributeBox.SelectedIndex != -1)
{
this.cardImage.Image = attributes[attributeBox.SelectedIndex];
}
How can I go about making it sort the resources in the resx alphabetically?
The return type of GetResourceSet, ResourceSet, implements IEnumerable, so you should be able to run some LINQ ordering on it:
foreach (var entry in cardResourceSet.Cast<DictionaryEntry>().OrderBy(de => de.Key))
{
}
Since you're iterating over it twice (though I'm not really sure of the point of the first for-loop, unless there's other code), you may want to assign the sorted results to a separate variable:
var sortedCardResourceSet.Cast<DictionaryEntry>().OrderBy(de => de.Key).ToList();
foreach (var entry in sortedCardResourceSet)
{
...
}
...
Related
I have a windows form application in c# where there are list of data in multiple listbox (around 56 in each listbox).
here is an example:
listbox1 contains data of name of students
listbox2 contains data of address of students
listbox3 contains percentage of students.
the list goes on with the student data.
Now i need to print the data in excel in a button click event.
the data should go in an ordered way .
I tried using the CSV helper but it only helped me for 1 set of list box i need to sent data from multiple list box.
var sw = new StreamWriter(#"output.csv");
var csvWriter = new CsvHelper.CsvWriter(sw);
foreach (var Name in lbx.Items)
{
csvWriter.WriteField(Name);
csvWriter.NextRecord();
}
foreach (var Address in ptr.Items)
{
csvWriter.WriteField(Address);
}
sw.Flush();
However, this doesn't solve the problem. Any help regarding the solution to this problem would be helpful.
Any other method to solve the problem will be great.
It's difficult for me to determine the full details of your configuration, but if it's as simple as two ListBox controls for which you're writing values, you could easily do something like the following:
var sw = new StreamWriter(#"output.csv");
var csvWriter = new CsvHelper.CsvWriter(sw);
int lbxCount = lbx.Items.Count;
int ptrCount = ptr.Items.Count;
for (int i = 0; i < Math.Max(lbx.Items.Count, ptr.Items.Count); i++)
{
object lbxValue = lbxCount > i ? lbx.Items[i] : String.Empty;
object ptrValue = ptrCount > i ? ptr.Items[i] : String.Empty;
csvWriter.WriteField(lbxValue);
csvWriter.WriteField(ptrValue);
csvWriter.NextRecord();
}
sw.Flush();
sw.Close();
This determines the maximum number of records to write (Math.Max(lbx.Items.Count, ptr.Items.Count) based on the greatest ListBox.Items.Count.
By altering your loops to be a single loop, you can now use the WriteField method correctly. If the ListBox lbx does not contain a value for a certain record, it uses a String.Empty as the value for that record. Likewise it does the same for ListBox ptr, in the event that there are more items in lbx.
If you have many ListBox controls on a single form and wish to each of them, you could determine the maximum items overall by iterating through all ListBox controls and getting their respective Item.Count values as follows:
var sw = new StreamWriter(#"output.csv");
var csvWriter = new CsvHelper.CsvWriter(sw);
int maxRecords = 0;
List<ListBox> listBoxes = new List<ListBox>();
// Add all ListBox controls to list
// Determine maximum number of items (in all ListBox controls)
foreach (Control control in Controls)
{
if (control.GetType() == typeof(ListBox))
{
ListBox currentListBox = (ListBox)control;
listBoxes.Add(currentListBox);
if (currentListBox.Items.Count > maxRecords)
maxRecords = currentListBox.Items.Count;
}
}
// Write fields for each ListBox
for (int i = 0; i < maxRecords; i++)
{
foreach (ListBox currentListBox in listBoxes)
{
if (currentListBox.Items.Count > i)
csvWriter.WriteField(currentListBox.Items[i]);
else
csvWriter.WriteField(String.Empty);
}
csvWriter.NextRecord();
}
sw.Flush();
sw.Close();
I'm using the ObjectListViewand am trying to add images to my items. I got it to work by looping through all the items and then manually editing the image index per item. I would like to know if this is possible when adding the items. This is the code I have at the moment:
Adding the items
for (int i = 0; i < listName.Count; i++)
{
games newObject = new games(listName[i], "?");
lstvwGames.AddObject(newObject);
}
Adding the images
foreach (string icon in listIcon)
{
imglstGames.Images.Add(LoadImage(icon)); // Download, then convert to bitmap
}
for (int i = 0; i < lstvwGames.Items.Count; i++)
{
ListViewItem item = lstvwGames.Items[i];
item.ImageIndex = i;
}
It is not entirely clear to me what exactly you try to achieve, but there are several ways to "assign" an image to a row. Note that you probably have to set
myOlv.OwnerDraw = true;
which can also be set from the designer.
If you have a specific image for each of your model objects, its probably best to assign that image directly to your object and make it accessible through a property (myObject.Image for example). Then you can use the ImageAspectName property of any row to specify that property name and the OLV should fetch the image from there.
myColumn.ImageAspectName = "Image";
Another way to do it is using the ImageGetter of a row. This is more efficient if several of your objects use the same image, because you can fetch the image from anywhere you want or even use the assigned ImageList from the OLV by just returning an index.
indexColumn.ImageGetter += delegate(object rowObject) {
// this would essentially be the same as using the ImageAspectName
return ((Item)rowObject).Image;
};
As pointed out, the ImageGetter can also return an index with respect to the ObjectListView's assigned ImageList:
indexColumn.ImageGetter += delegate(object rowObject) {
int imageListIndex = 0;
// some logic here
// decide which image to use based on rowObject properties or any other criteria
return imageListIndex;
};
This would be the way to reuse images for multiple objects.
Both your approach and the one I show below will have problems if the list is ever sorted as sorting will change the order of the objects in the list. But really all you have to do is keep track of your object count in your foreach loop.
int Count = 0;
foreach (string icon in listIcon)
{
var LoadedImage = LoadImage(icon);
LoadedImage.ImageIndex = Count;
imglstGames.Images.Add(LoadedImage); // Download, then convert to bitmap
Count++;
}
I've made a program where you can add text over textbox and it adds it into a listbox. Now to actually save it on the next time when the application launches, I decided to store it into some text.ini file.
Now that the next time the application launches (form load), using the StreamReader it reads all the text from that file and displays it into a listbox.
I have decided to implement an edit functionality (select the item from listbox -> right click -> edit), and rename the file (in case something was misspelled).
My problem is this:
If I have 1 item in the listbox and rename it, it works perfectly fine.
But if I have 2 or more items in the listbox but decide to rename only 1, it removes all text from the file and renames only the selected item.
This is my code:
string itemName = (string)lBoxRadioLinks.SelectedItem;
var renameFile = Interaction.InputBox("Enter a new name for the file:", "Rename File", itemName);
// Gets the selected item full name
var url = lBoxRadioLinks.GetItemText(lBoxRadioLinks.SelectedIndex);
string lineToRename = url.ToString();
// Selected file
//MessageBox.Show(lineToRename);
// ACTUALLY rename the text
string[] lines = File.ReadAllLines("IO/sites.ini");
List<string> list = new List<string>();
foreach (string line in lines)
{
if (line != lineToRename)
list.Add(line);
}
// Have to convert the string into array for an actual rename
string[] arr = new string[] { renameFile };
// Visually rename the file (display in listbox asap)
lBoxRadioLinks.DataSource = arr;
// Renames the file
File.WriteAllLines("IO/sites.ini", arr);
Obviously the method "WriteAllLines" will rename the whole text inside of a file, but I don't want that.
How can I rename a text that is at a certain line, without effecting other lines in a file?
I don't really know what you're asking, but I'll give this my best shot.
If we're understanding each other when we agree that you want to replace certain text in a text file, and if you're actually okay loading the whole thing into memory, then you might as well just use the string.Replace method.
Dictionary<string, string> changesToMake = ...;
var contents = File.ReadAllText(filename);
foreach(var change in changesToMake)
{
contents = contents.Replace(change.Key, change.Value);
}
File.WriteAllText(filename, contents);
As for the problem you're having with multiple items in the ListBox, you're only referencing the SelectedItem and SelectedIndex properties, so nothing should get changed anywhere other than at those...files? I'm still not even sure of what's in that ListBox. If you want to alter more than one at a time, you should be using the pluralized forms of each of those properties to access all of the selected items and not just the first.
I have a listview with few items. I am using foreach loop to check if there is a match. The code I am using looks like this:
foreach (ListViewItem test in listView1.Items)
{
if (test.SubItems[1].ToString() == item.SubItems[1].ToString())
{
test.Tag = item.Tag;
}
}
What I am trying to do is, check the 2nd index and if there is a match replace the old item 'test' with the new one 'item'.
Apparently there is no change in the listview. Is the way I am replacing the object wrong?
you can clone the item and assign directly to the list view item. but you need to change foreach loop to for loop.
for (int i = 0; i < listView1.Items.Count; i++)
{
if (listView1.Items[i].SubItems[1].ToString() == item.SubItems[1].ToString())
{
listView1.Items[i] = (ListViewItem)item.Clone();
}
}
You have updated the Tag only. You need to change test.SubItems[0], test.SubItems[1],... to see the changes.
Or you could remove old item and insert new item by using listView1.Items.Remove(...) or listView1.Items.RemoveAt(...) and listView1.Items.Insert(...). But if you need to pay account of performance you should use the first algorithm (changing test.SubItems[i]).
I have an Array List to save selected files and a ListBox to display only the name of the files..my requirement is to delete corresponding files from arraylist when its deleted from listbox...here is my code:
public ArrayList to_compress = new ArrayList();
ListBox pack_lbx=new ListBox();
private void add_btn_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Multiselect = true;
if (ofd.ShowDialog() == DialogResult.OK)
{
foreach (string f in ofd.FileNames)
{
FileInfo f_inf = new FileInfo(f);
if (pack_lbx.Items.IndexOf(Path.GetFileName(f)) == -1)
{
to_compress.Add(new string[] { f, f_inf.Name });
pack_lbx.Items.Add(Path.GetFileName(f));
}
}
}
private void remove_btn_Click(object sender, EventArgs e)
{
// pack_lbx.Items.Remove(pack_lbx.Items);
ListBox.SelectedObjectCollection s = pack_lbx.SelectedItems;
while (s.Count > 0)
{
pack_lbx.Items.Remove(s[0]);
to_compress.Remove(s.ToString()); //this doesnt work
}
}
I don't see a question here. I'm assuming that you're getting an error because you're trying to modify a collection that you're actively looping through?
If that's NOT the issue, please change this to a question so that we can give a better answer.
However, assuming I am guessing right...
You can't do that... It messes up things if you alter the list you're looping through.
Instead, you should be creating a NEW list and adding items to it (copying them from the list you're looping through as you're looping through it) and just skipping the "add" code for the items you want to "delete".
while (s.Count > 0)
{
pack_lbx.Items.Remove(s[0]);
to_compress.Remove(s.ToString());//this doesnt work
}
this will not work because , you are deleting object from a collection while looping through the collection so
do this
private void remove_btn_Click(object sender, EventArgs e)
{
// pack_lbx.Items.Remove(pack_lbx.Items);
ArrayList tempList = new ArrayList();
ListBox.SelectedObjectCollection s = pack_lbx.SelectedItems;
foreach(string str in to_compress)
{
if(!s.Contains(str))
tempList.Add(str)
}
to_compress = tempList;
}
Trying to keep two identical lists synchronised is a pattern that opens you up to bugs, because if you fail to synchronise correctly in just one place, your UI will be displaying information that is different from what your program is using internally.
A better approach is to only keep one "master" list. Let the ListBox hold the list, manipulate it in the ListBox, and only copy the filenames out of the ListBox at the end of the process.
If you want the text displayed in the listbox to be different from the underlying string (e.g. display leafnames in the box but keep full pathnames internally) then you can create a trivial class to hold the full pathname and override its ToString() to return the leafname. Then add instances of this class rather than raw strings to the ListBox.
If you insist on keeping two lists in sync, then the easiest is to use ListBox.SelectedIndex with the RemoveAt() method, and simply remove the same item from both lists.
If you need to remove an item from a list that you are enumerating, you can either:
Use a for loop with an index instead of foreach to do the iterating. You can then acess list items with the array index [i] syntax, and delete them with RemoveAt(i). Just be careful with how you advance the index after deleting an item.
Use a separate variable/list to store references to the items you wish to delete during your first loop, and then execute a second loop over this list to actually do the deletion as a post-processing step.
to_compress.Remove(s[0].ToString());
I can't see any line of code that add the files to the ArrayList to_compress.
Also if you adding the FileInfo object to arraylist you can't remove it using the name of the file.
Consider using generic dictionary that have name of file as key and the actual file object as value.
var to_compress = new Dictionary<string,FileInfo>();
to_compress.Add(filename,File);
//then you can remove by
to_compress.Remove(filename);
//you can loop through it like so
foreach (var pair in to_compress)
{
string filename = pair.Key;
FileInfo file = pair.Value;
}