select row from winforms listview - c#

I have listview which is populated with list of data. Now I want to select desired row and on click button to recognize that item to delete from a collection.
Question is how to recognize selected row from the listview?
private void buttonDelete_Click(object sender, EventArgs e)
{
//selected data is of custom type MyData
var selected = (MyData)....?
}
Thanks

This should works
private void buttonDelete_Click(object sender, EventArgs e)
{
//selected data is of custom type MyData
var selected = yourListView.SelectedItems.First();
}

To add to #Zaphod's answer and make a little more robust:
private void buttonDelete_Click(object sender, EventArgs e)
{
if (yourListView.SelectedItems.Any())
{
//selected data is of custom type MyData
var selected = yourListView.SelectedItems.First();
}
}
You could use .Count > 0 instead of .Any() and .SelectedItems[0] instead of .First(). Whatever you find more readable/maintainable.

Old School answer :) without any LINQ statements
if(yourListView.SelectedItems.Count > 0)
{
var item = yourListView.SelectedItems[0];
}

I don't think you have to use casting for a deleting operation, just remove all the selected indices like this:
private void buttonDelete_Click(object sender, EventArgs e){
for (int i = listView1.SelectedIndices.Count - 1; i >= 0; i--)
listView1.Items.RemoveAt(listView1.SelectedIndices[i]);
}
or more simply:
private void buttonDelete_Click(object sender, EventArgs e){
foreach(ListViewItem item in listView1.SelectedItems)
listView1.Items.Remove(item);
}
As you can see the item which is selected is of type ListViewItem, you can bind your data to this item via Text property (if the data is string) or Tag property. I don't understand what your CustomData is, is it a type inheriting ListViewItem?

YOu should do this
private void buttonDelete_Click(object sender, EventArgs e)
{
if (yourListView.SelectedItems.Any())
{
//selected data is of custom type MyData
var selected = (MyData)yourListView.SelectedItems[0];
YourCollection.Remove(selected);
}
}

Related

How to add and remove values from ComboBox to CheckedListBox

What I need:
I need a ComboBox and a CheckedListBox with exact same values.
I have a Button to add values and delete values.
Here is my Add Button:
private void button5_Click(object sender, EventArgs e)
{
checkedListBox1.Items.Add(comboBox1.Text);
comboBox1.Items.Add(comboBox1.Text);
comboBox1.Text = "";
}
and my Delete Button:
private void button6_Click(object sender, EventArgs e)
{
comboBox1.Items.Remove(comboBox1.SelectedItem);
}
I would like to be able to delete the entries in the CheckedListBox without having to select it first, I only need it to be selected into the comboBox1.
Since you're adding the same strings, you can use the IndexOf() method to get the index where the current string is located in your CheckedListBox and the RemoveAt() to remove it.
Verify that the ComboBox.SelectedItem is not null. You can use the GetItemText() method to get the string currently selected. If the SelectedItem is null, you get back a empty string.
private void button6_Click(object sender, EventArgs e)
{
string currentItem = comboBox1.GetItemText(comboBox1.SelectedItem);
if (!string.IsNullOrEmpty(currentItem))
{
checkedListBox1.Items.RemoveAt(checkedListBox1.Items.IndexOf(currentItem));
comboBox1.Items.Remove(comboBox1.SelectedItem);
}
}
Method2:
If the Items it the two controls are located at the same index, you can instead use the ComboBox.SelectedIndex to RemoveAt() both:
private void button6_Click(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex >= 0)
{
checkedListBox1.Items.RemoveAt(comboBox1.SelectedIndex);
comboBox1.Items.RemoveAt(comboBox1.SelectedIndex);
}
}

Sync. SelectedIndex of two multiselect Listboxes

I'm strungling to sync. the selectedIndexs of two multi-select Listboxes.
With single-select enabled the code is just:
private void libHT_SelectedIndexChanged(object sender, EventArgs e)
{
libMonth.SelectedIndex = libHT.SelectedIndex;
}
But this doesn't work if multi-select is enabled.
Can you help me? Do I have to use a for or foreach?
Thanks for your help.
Thomas
There is the SelectedIndices property.
private void libHT_SelectedIndexChanged(object sender, EventArgs e)
{
libMonth.SelectedIndices.Clear();
foreach (var index in libHT.SelectedIndices.Cast<int>())
{
libMonth.SelectedIndices.Add(index);
}
}
Try that
Yes, you will have to loop over all the selections. Code like below can help you with that
private void libHT_SelectedIndexChanged(object sender, EventArgs e) {
libMonth.SelectedIndices.Clear();
foreach (int indx in libHT.SelectedIndices)
libMonth.SelectedIndices.Add(indx);
}
Don't forget:
To hook the index changed event: libHT.SelectedIndexChanged += libHT_SelectedIndexChanged;
To set the selection mode correctly libHT.SelectionMode = libMonth.SelectionMode = SelectionMode.MultiExtended;
To watch out for your programmatic selection, causing infinite recursion

How to access the object a selected row is representing?

I have a SortablebindingList<Record> as a DataSource for my DataGridView. I also have dataGridView.CellContentDoubleClick mapped to my selectionDblClicked() fuction.
dataGridView.CellContentDoubleClick += new System.Windows.Forms.DataGridViewCellEventHandler(selectionDblClicked);
...
void selectionDblClicked(object sender, EventArgs e)
{
//Do something with the underlying `record` object...
}
Now, EventHandlers pass a sender object and an EventArgs argument.
My question is how does one use the DataGridViewCellEventHandler to access the underlying object that was "double clicked"?
Use the DataBoundItem property of the clicked row.
To see which row was clicked, use RowIndex property of DataGridViewCellEventArgs.
void selectionDblClicked(object sender, DataGridViewCellEventArgs e)
{
var rowClicked = dataGridView.Rows[e.RowIndex];
DoSomething(rowClicked.DataBoundItem as Record);
}

I want to show any selected item from CheckedListBox in a ListBox in C#

I have a windows form application that contains one "CheckedListBox" named "ChkBox1" and it contains this items (Blue, Red, Green, Yellow).
The form contains also an empty "ListBox" named "LstBox1".
I want when i check any item from "ChkBox1" it add to "LstBox1" and when i unchecked it from "ChkBox1" it removed from "LstBox1".
I think i should use "ItemChecked" event but i don't know how can i detect if the item checked or not and add it to another list.
This is my try:
private void ChkBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
if (ChkBox1.CheckedItems.Count > 0)
listBox1.Items.Add(ChkBox1.Items[e.Index]);
else if (ChkBox1.CheckedItems.Count == 0)
listBox1.Items.Remove(ChkBox1.Items[e.Index]);
}
but it add the item when i unchecked it not when i check it.
and this is another try:
private void ChkBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
if (ChkBox1.GetItemChecked(e.Index) == true)
listBox1.Items.Add(ChkBox1.Items[e.Index]);
else if (ChkBox1.GetItemChecked(e.Index) == false)
listBox1.Items.Remove(ChkBox1.Items[e.Index]);
}
Try this:
private void ChkBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
if (e.NewValue == CheckState .Checked)
{
listBox1.Items.Add(ChkBox1.Items[e.Index]);
}
else
{
listBox1.Items.Remove(ChkBox1.Items[e.Index]);
}
}
The "ItemChecked" will send you an "ItemCheckEventArgs" that contains both the old and the new value.
It also contain the index of the value that has changed.
You can also check the "CheckedItems" property to get every checked items :
private void ChkBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
LstBox1.Items.Clear();
foreach (var item in ChkBox1.CheckedItems)
LstBox1.Items.Add(item);
}

How can I create only one event handler method for multiple controls?

I have 15 comboBox'es, and I do not want to create an event handler for each. How do I make just one procedure and tie all Combobox'es to it?
private void cbSlots0_SelectedIndexChanged(object sender, EventArgs e)
{
var item = ConfigClass.Slots["0"][cbSlots0.SelectedIndex];
ConfigClass.Slots["0"].Insert(0, item);
ConfigClass.Slots["0"].RemoveAt(cbSlots0.SelectedIndex + 1);
}
private void cbSlots1_SelectedIndexChanged(object sender, EventArgs e)
{
var item = ConfigClass.Slots["1"][cbSlots1.SelectedIndex];
ConfigClass.Slots["1"].Insert(1, item);
ConfigClass.Slots["1"].RemoveAt(cbSlots1.SelectedIndex + 1);
}
Correct answer:
var cb = ((ComboBox)sender);
var tag = int.Parse(cb.Tag.ToString());
var item = ConfigClass.Slots[tag.ToString()][cb.SelectedIndex];
ConfigClass.Slots[tag.ToString()].Insert(tag, item);
ConfigClass.Slots[tag.ToString()].RemoveAt(cb.SelectedIndex + 1);
You can give each ComboBox a distinct Tag, which contains the number of the entry in the ConfigClass, and then use that like so:
private void cbSlots0_SelectedIndexChanged(object sender, EventArgs e)
{
int tag = (int)((ComboBox)sender).Tag;
var item = ConfigClass.Slots[tag.ToString()][cbSlots0.SelectedIndex];
ConfigClass.Slots[tag.ToString()].Insert(tag, item);
ConfigClass.Slots[tag.ToString()].RemoveAt(cbSlots0.SelectedIndex + 1);
}
The tag can contain any data you want, so if you need something more complex stored in there, that's also a possibility.
I would recommend one event handler for all ComboBoxes. Afterwards, within your event handler, use the sender reference to decide which slot to use:
private void allComboBoxesSelectedIndesChanged(object sender, EventArgs e)
{
int index = 0; // Or string as you have shown in your example.
if (sender == cbSlots0)
index = 0;
else if (sender == cbSlots1)
index = 1;
/// And so on for any other comboBox
var item = ConfigClass.Slots[index][((ComboBox) sender).SelectedIndex];
ConfigClass.Slots[index].Insert(index, item);
ConfigClass.Slots[index].RemoveAt(((ComboBox) sender).SelectedIndex +1);
}
This is relatively simple. You create a single SelectedIndexChanged event handler method, and then wire that up to all of the combo box controls.
The way you distinguish between the controls inside of the method at run-time is by checking the value of the sender parameter. You'll have to cast it to a ComboBox control, but that's safe because you know that you didn't wire up any non-combobox controls to that event handler. Then you'll be able to access all the properties of the combobox that raised the event you're handling.
Tie each item in your markup to the same SelectedIndexChangedEvent and cast the sender as your item. So, in your code, look for all of the unique event names (ie. cbSlots0_SelectedIndexChanged, cbSlots1_SelectedIndexChanged, etc) and rename them to the single event name (eg. cbSlotsSelectedIndexChanged).
I think this is right. Verify.
CODE:
private void cbSlotsSelectedIndexChanged(object sender, EventArgs e)
{
ComboBox cBox = (ComboBox) sender;
int tag = (int)cBox.Tag;
var item = ConfigClass.Slots[tag.ToString()][cBox.SelectedIndex];
ConfigClass.Slots[tag.ToString()].Insert(tag, item);
ConfigClass.Slots[tag.ToString()].RemoveAt(item.SelectedIndex + 1);
}
UPDATE:
I revised my post as requested
private void cbSlotsSelectedIndexChanged(object sender, EventArgs e)
{
var cb = ((ComboBox)sender);
var tag = int.Parse(cb.Tag.ToString());
var item = ConfigClass.Slots[tag.ToString()][cb.SelectedIndex];
ConfigClass.Slots[tag.ToString()].Insert(tag, item);
ConfigClass.Slots[tag.ToString()].RemoveAt(cb.SelectedIndex + 1);
}

Categories