Deleting files from ArrayList in C# - c#

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;
}

Related

Filtering listbox using textbox using Linq but listbox stays full

I am unable to filter listbox data using linq and textbox.Listbox values don 't change when I enter text to be filtered inside the textbox. This function is important so that I can send the data to another form which contains the listbox.
public void GetList(List<SemesterDetails> modules)
{
string filter = txtFilter.Text;
foreach (var item in modules.Where(m => m.ModuleName.Contains(filter)))
{
LstModules.Items.Add(item);
}
}
I tried to call the function to the textbox event function:
private void txtFilter_TextChanged(object sender, TextChangedEventArgs e)
{
List<SemesterDetails> semesters = new List<SemesterDetails>();
GetList(semesters);
}
The result is:
Items remain unfiltered in the listbox.
List<SemesterDetails> semesters = new List<SemesterDetails>();
GetList(semesters);
This is an empty list.
public void GetList(List<SemesterDetails> modules)
{
string filter = txtFilter.Text;
foreach (var item in modules.Where(m => m.ModuleName.Contains(filter)))
{
LstModules.Items.Add(item);
}
}
Since you're passing in an empty list, the foreach will be executed 0 times, and therefore nothing can ever be added.
The filtering is irrelevant in this scenario.
Items remain unfiltered in the listbox
Nowhere in your code do you ever remove the items that are already in the listbox. Therefore, it's not possible for the listbox' contents to reduce.
When I add clear Listbox prior, I get no items
If you clear a list and then not add items to it (as discussed above), an empty list is indeed the logical outcome.

How to populated C# listbox with string separated comma

I have a string that separated by comma like this:
"test1,test2,test3"
and i want to convert those string to list with folowing code :
private void convertToList()
{
try{
List<string> myList = occ.Split(',').ToList();
listBox1.Items.Add(myList);
}catch(Exception e){
MessageBox.Show(e.Message);
}
}
I think that code will convert the string into a list and add it into a Listbox, instead, it shows only "collection"(yes only show the word "collection", nothing more) not the actual list.
why that's happened? can you tell me what's the right code?
Well, Add adds a single item which is a List<string> in your case. What should ListBox show for this? Collection seems to be a good enough solution. If you want to add entire collection in one go, try AddRange:
listBox1.Items.AddRange(occ.Split(','));
If you insist on Add, you have to loop in order to Add each item of the collection:
// To stop unwanted redrawing after each item addition
listBox1.BeginUpdate();
try {
foreach (var item in occ.Split(','))
listBox1.Items.Add(item);
}
finally {
listBox1.EndUpdate();
}

Delete from one, add to another Listbox and vice versa with the same sorting like before

I have to small events to delete the selected items from one list and add them to another and vice versa and it works fine.
The Problem is that when i delete the items from the second list and add them again to the first list that the sorting is add the end of the list.
Is it possible to save the "position" to add them on the same place like before?
Solutions like list.sort() wouldn't work because its a database with all tables and triggers and so on...
private void LstSelectedDbTables_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
if (lstSelectedDbTables.SelectedIndex != -1)
if (e.KeyValue == (char) Keys.Delete || e.KeyValue == (char) Keys.Back)
{
var selectedItems = lstSelectedDbTables.SelectedItems;
var bdHashSet = new List<string>(lstSourceDatabaseTables.Items.Cast<string>());
for (int i = selectedItems.Count - 1; i >= 0; i--)
{
bdHashSet.Add(selectedItems[i].ToString());
lstSelectedDbTables.Items.Remove(selectedItems[i]);
}
lstSourceDatabaseTables.DataSource = bdHashSet;
}
}
private void lstSourceDatabaseTables_DoubleClick(object sender, EventArgs e)
{
if (lstSourceDatabaseTables.SelectedIndex != -1)
{
var bdHashSet = new HashSet<string>(lstSourceDatabaseTables.Items.Cast<string>());
var selectedItems = lstSourceDatabaseTables.SelectedItems;
for (int i = selectedItems.Count - 1; i >= 0; i--)
{
lstSelectedDbTables.Items.Add(selectedItems[i]);
bdHashSet.Remove(selectedItems[i].ToString());
}
lstSourceDatabaseTables.DataSource = bdHashSet.ToList();
}
}
You can't add items to List<T> to specific place in your list, beacuse List<T>.Add()
Adds an object to the end of the List.
You could create simple List not attached to database context in any way, do your operations like inserting and deleting and then pass list which is correctly ordered to save in your database. Then you could use Sort or OrderBy since these methods are designed to perform exactly, what you are asking for.
you must made a list of array when the first column is "last index position" and the other column is "itemvalue"...so every time that you move an item from a list box to other you must copy in another list called temp of the same type all the elements of destination listbox from index n+1 until the end and delete each one after copied. Then insert the new element that you want move and insert all the item of temp list.

ArgumentOutOfRangeException when looping with foreach and counter variable into ListView?

I have a multiselect OpenFileDialog which is looping through every line in multiple files and keeping count in order to do specific work by Index. How do I stop it from giving me an ArgumentOutOfRangeException when loading more than 1 file? Listview is already populated with items and subitems collection into two additional headers. The two files combined will only be loading about 6 items into column [1].
public void LoadStudents()
{
var ofdLoadStudents = new OpenFileDialog();
ofdLoadStudents.Multiselect = true;
int Counter = 0;
if (ofdLoadStudents.ShowDialog() == DialogResult.OK)
{
foreach (string studentList in ofdLoadStudents.FileNames)
{
foreach (string Students in File.ReadAllLines(studentList))
{
//[Period 1] | [ReadAllLines Data]
//listview already populated with 10 items, and subitems with "" as the item.
//only loading total of 6 lines with 2 files, into [1] column.
listViewStudents.Items[Counter].SubItems[1].Text = Students;
Counter++;
}
}
}
}
An "ArgumentOutOfRangeException" can be caused when attempting to access an element outside of an collection. For instance, let's say you have a List with 5 ints inside of it. Now, let's say you try to access element 7. There is no element seven, so you will get an ArgumentOutOfRangeException.
There are two places I see in your above code that could cause this problem, and they are both on the same line:
listViewStudents.Items[Counter].SubItems[1].Text = Students;
The first problem location is the listViewStudents.Items[Counter] part. The Items object in listViewStudents is a collection which must have objects added to it before accessing them. If you don't add any objects to "Items", or if your Counter variable gets too large you will try to access an element of the Items object which does not exist, so you will get the error. This is where I think the problem most likely is. Where are you adding items to the listViewStudents.Items collection? Is it somewhere else in your code? Make sure this is initialized before trying to access the elements. Also, if you are adding them somewhere else in your code, how do you know that the number of lines in the text file you are reading does not exceed the number of elements in the Items collection? These are the things you need to take in to account when dealing with any type of collection.
The second problem location is in the SubItems[1] part. SubItems is also a collection, and if it is not initialized with at least two elements (you're accessing the second element by calling SubItems[1], it starts with SubItems[0]) then you will also get an ArgumentOutOfRangeException.
So your problem is not with your foreach loops, they look fine.
EDIT:
I quickly wrote some code that implements what I think you're trying to do. Are you trying to read a list of student names and add them to a WinForm ListView control? If so, this code will do that.
public void LoadStudents()
{
var ofdLoadStudents = new OpenFileDialog();
ofdLoadStudents.Multiselect = true;
int Counter = 0;
if (ofdLoadStudents.ShowDialog() == DialogResult.OK)
{
foreach (string studentList in ofdLoadStudents.FileNames)
{
foreach (string Students in File.ReadAllLines(studentList))
{
//[Period 1] | [ReadAllLines Data]
//has about 10 items | all "" fields.
//only loading total of 6 lines with 2 files combined.
listViewStudents.Items.Add(new ListViewItem(new string[] { Counter.ToString(), Students })); //This is the new code
Counter++;
}
}
}
}
This will lead to a listView which displays a series of numbers 0,1,2... up to the number of lines in the text file.
If you want to display the student name instead then flip around the Students and Counter.ToString() elements in the array.
listViewStudents.Items.Add(new ListViewItem(new string[] { Counter.ToString(), Students }));

ListView Hidding rows

My requirement is to hide specific rows in a ListView. Since there is no inbuilt functionality I was using the ListView_DrawItem Event to hide the specific rows. I was able to hide the rows but the issue is there is a balnk space coming if i add a row post to the hidden row.
Please find the below code:
ListViewItem LVI = listView1.Items.Add("1");
LVI.SubItems.Add("Srikanth");
ListViewItem LVI1 = listView1.Items.Add("2");
LVI1.SubItems.Add("Suresh");
private void listView1_DrawItem(object sender, DrawListViewItemEventArgs e)
{
if (e.Item.Text != "2")
{
e.DrawDefault = true;
}
}
Output Looks Like
1 Srikanth
3 Sandy
Would like to remove the space b/w 1 & 3 record
Any help is appreciated
You are not really hiding the items, that is plain to see. Instead, you are offering to draw them yourself, and passing some off to default rendering. The items are there regardless.
My approach would be to manipulate the collection, adding only those items that the list box needs to deal with.
Depending on the data you have at hand, keep a local copy of the full list, in order, such as in a generic List<YourDataClass>. Also, keep a list of 'hidden' indexes.
Respect the order of List<T> and loop across it, only adding new ListViewItem objects for those indexes not present in the 'hidden' list.
private List<String[]> _listItems = new List<String[]>();
private List<Int32> _hiddenIndexes = new List<Int32>();
private void UpdateCollection()
{
listBox.Items.Clear();
for (Int32 i = 0; i < _listItems.Count; i++)
{
if (!_hiddenIndexes.Contains(i))
listBox.Items.Add(new ListBoxItem(_listItems[i]));
}
}
Beware that if this happens to be a list with a very large number of items, it might not be the most efficient approach.

Categories

Resources