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.
Related
I wish for my ListBox to update the old values with new values rather than simply adding more and more lines to the ListBox like it does at the moment. However, I'm not sure where to look to implement something that can handle this.
My current code looks like this:
private void DisplayText(string rawData)
{
textArduinoData.Text = rawData;
string[] sortedData = rawData.Split(';');
for (int i = 0; i < sortedData.Length; i++)
{
listPortData.Items.Add(sortedData[i].ToString());
}
}
Could someone please point me in the right direction to implementing this update feature? Any advice would be much appreciated.
You need to manage the process. It is easy in concept but depending on how much data is needed to be processed, it could get slow quickly. Steps
Create a specialized token class which implements to INotifyPropertyChanged.
Have an ObservableCollection hold the class items from #1. The observable collection notifies the ListBox when an item is added or removed. This will allow your code to add items one at a time. (Solves 1 problem)
To solve the next problem of data changing: Have a property named Text, on the class in #1 which will hold the data, provide a property change notification.
In the list box bind to the list of items created in step 1 and specify to bind to the Text. Use of a data template for the listbox will allow you to bind to the Text property of the list's instance.
Provide the heuristics/ smarts to read incoming data and find the associated data in the observable collection from step 2. When found change the Text property of the existing data to the new and the binding of that list item will change accordingly.
You could check if the ListBox contains the string using the IndexOf method and then update the existing string (or simply do nothing) or add a new one depending on whether you get an index other than the default value of -1 back:
private void DisplayText(string rawData)
{
textArduinoData.Text = rawData;
string[] sortedData = rawData.Split(';');
int index;
for (int i = 0; i < sortedData.Length; i++)
{
if ((index = listPortData.Items.IndexOf(sortedData[i])) == -1)
{
listPortData.Items.Add(sortedData[i]);
}
}
}
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.
how Select the row index in datagrid ?
The event SelectionChanged
The following code does not work :
private DataGridRow dgr = new DataGridRow();
private void dataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
this.dgr = this.dataGrid.ItemContainerGenerator.ContainerFromItem(this.dataGrid.SelectedItem) as DataGridRow;
MessageBox.Show(this.dgr.GetIndex().ToString());
}
The reason why above code would not work is because wpf data grid is virtualized and it may not return the row using the itemContainerGenerator.ContainerFromItem because it may be lying outside the scroll view.
For this you will have to use the datagrid's items collection and the IndexOf call using selected item.
private void dataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var dg = sender as DataGrid;
MessageBox.Show(dg.Items.IndexOf(dg.SelectedItem).ToString());
}
My answer is late, but I hope it still will be useful for people who found this post from search engines. This is more general solution which also helps to define indexes of all the selected rows.
List<int> RowIndexes = new List<int>();
int SelectedItemsCount = yourDataGrid.SelectedItems.Count;
for (int i = 0; i < SelectedItemsCount ; i++)
{
RowIndexes.Add(yourDataGrid.Items.IndexOf(yourDataGrid.SelectedItems[i]));
}
And now RowIndexes contains all indexes of the selected rows. Just put the code inside the event you wish, that's all.
This is a late answer, but this is how I accomplished it. This gives you index of every selected row in the DataGrid (dgQuery is the name of my DataGrid):
foreach (var selection in dgQuery.SelectedItems)
{
DataRowView row = (DataRowView)item;
int index = Convert.ToInt32(row.Row[0]) - 1;
}
It gives 1 at index 0, so we need to subtract 1 at every index.
.Row[0] Is actually a column (in my head)... of that DataRowView, not sure why it's called a row. You can change it to [1], [2] and so on to view other cells within that row.
With this solution, you don't need a collection, array, nothing of that sort. You just work with what's at hand and make use of existing code.
The huge plus side of this implementation, at least for me, was the fact that it goes through selected items in the order they were selected. This can be a very powerful tool if you wish to know the order of user's selection.
I'm posting this because I just spent over 4 hours looking for a solution. I even gave up on check boxes because I don't have enough time to implement those to work well... maybe down the road.
I've just started to use ListView in C#.net.
I got to know how to add items and subitems. Going through the listview I wanted to fetch all the data from a whole column with multiple rows.
I want to know how to do this.
I found this code to list a specific selected data from a row:
ListView.SelectedIndexCollection sel = listView1.SelectedIndices;
if (sel.Count == 1)
{
ListViewItem selItem = listView1.Items[sel[0]];
MessageBox.Show(selItem.SubItems[2].Text);
}
That was helpful but i want to list all the items in a row, may be i want to add all the column items in array?
private string[] GetListViewItemColumns(ListViewItem item) {
var columns = new string[item.SubItems.Count];
for (int column = 0; column < columns.Length; column++) {
columns[column] = item.SubItems[column].Text;
}
return columns;
}
I would recommend some caution against doing this. A ListView is really meant to display information, it is not a great collection class. Getting the data out of it is slow and crummy, it can only store strings. Keep the data in your program in its original form, maybe a List<Foo>. Now it is simple and fast.
foreach (ListViewItem item in listView1.Items) {
// Do something with item
}
you could do this by
foreach(ListViewItem item in listView1.Items)
{
foreach(var subtem in item.SubItems)
{
// Do what ever you want to do with the items.
}
}
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;
}