Cloning items in a listbox c# - c#

I have 2 list boxes and want to be able to copy selected items from one to the other how ever many times I want. Ive managed to do this but I have buttons on the 2nd list box that allow me to go up and down..Now when theres to items in the second list box that are the same (e.g "gills" and "gills") it doesnt behave normally and crashes.
Is there a way in which I can get them to act as seperate items in the 2nd listbox?
code
private void buttonUp_Click(object sender, EventArgs e)
{
object selected = listBox2.SelectedItem;
int index = list2.Items.IndexOf(selected);
listBox2.Items.Remove(selected);
listBox2.Items.Insert(index - 1, selected);
listBox2.SetSelected(index - 1, true);
}
private void buttonAdd_Click(object sender, EventArgs e)
{
DataRowView selected = (DataRowView)listBox1.SelectedItem;
string item = selected["title"].ToString();
listBox2.Items.Add(item);
}
It works fine when i havnt got duplicates but when i do they just jump around randomly when i press up/down.
(ive not included down as its pretty much the same as up)

It seems like you're travelling around the world to do something simple. I would approach this using List and databinding the list.
// Add code
DataRowView selected = listBox1.SelectedItem as DataRowView;
if (selected != null)
{
_myList.Add(selected); // Adds at end
BindList2();
}
// Move up code
int selectedIndex = listBox2.SelectedIndex;
if(selectedIndex > 0)
{
var temp = _myList[selectedIndex];
_myList.Remove(temp);
_myList.InsertAt(selectedIndex - 1, temp);
BindList2();
}
// BindList2
public void BindList2()
{
listBox2.DataSource = _myList;
listBox2.DataBind();
}

You can use SelectedIndex instead of SelectedItem when you have multiple items that are all equal. I also recommend checking that it's not -1.

The problem for the up case is the following set of code.
object selected = listBox2.SelectedItem;
int index = list2.Items.IndexOf(selected);
This code will only function correctly if you have unique items in the list. Once you have duplicate items the value index will be the index of the first instance of say gills in the list and not necessarily the index of the selected value.
It seems like you mirror the items in listBox2 and list2. If that is the case then you can just use the SelectedIndex property directly on listBox2 since the index will be equal in both liss.
int index = listBox2.SelectedIndex;

If you are trying to use an list of objects, try implementing the Iclonnable. This will make copies of the same item over & over. Also note to move an item to the top or bottom you don't have to remove the item in the list & reinsert them back. But you can change the index of the item. Hope this helps.

Just the code, because the rest of the answers cover it anyways:
private void buttonAdd_Click(object sender, EventArgs e)
{
DataRowView selected = listBox1.SelectedItem as DataRowView;
if (selected != null)
{
string item = selected["title"].ToString();
listBox2.Items.Add(item);
}
}
private void buttonUp_Click(object sender, EventArgs e)
{
string selected = listBox2.SelectedItem as string;
int oldIndex = listBox2.SelectedIndex;
int newIndex = oldIndex;
if (!string.IsNullOrEmpty(selected) && listBox2.Items.Count > 1 && oldIndex > 0)
{
listBox2.SuspendLayout();
listBox2.Items.RemoveAt(oldIndex);
newIndex = oldIndex - 1;
listBox2.Items.Insert(newIndex, selected);
listBox2.SelectedIndex = newIndex;
listBox2.ResumeLayout();
}
}

Related

Use previous and next buttons to navigate items in a drop down list

I'm trying to create previous and next buttons on a page to navigate through items in a drop down list. Clicking next should select the next item in the DDL and clicking previous should go to the previous item.
Here's something I've attempted for the next button but it just takes me to the last row.
protected void btnNext_Click(object sender, EventArgs e)
{
int currentSelection = DDL.SelectedIndex;
for (int i = currentSelection; i < DDL.Items.Count; i++)
{
string nextSelection = (DDL.Items[i].ToString());
DDL.SelectedValue = nextSelection;
}
}
You're looping through all the items in the list until you get to the last one, and selecting each item individually until the loop exits. Drop a breakpoint inside that loop and debug to see what I mean.
You don't need any looping here at all. What you'd want instead would be simply:
int nextIndex = DDL.SelectedIndex + 1;
if (nextIndex + 1 >= DDL.Items.Count)
return; // We're on the last item, do nothing (or whatever you like)
DDL.SelectedValue = DDL.Items[nextIndex].ToString();
You easily can change selected value by its index so you don't need change it by its value.
int i = ddl.SelectedIndex;
if (i+1!=ddl.Items.Count)
{
ddl.SelectedIndex = i + 1;
}
else
{
ddl.SelectedIndex = i;
}
as you said in comment it wont change index if the current index is the last one.

c# Check pre-populated Checklistbox Items based on String or List of strings

We have a c# Winforms project in Visual studio 2017.
When a form loads, it populates a checklistbox control with values from the settings.
By default all the items inside the checklistbox are unchecked.
With another button later on we get a string separated by commas for example (apple,oranges,kiwies)
What we want to do is if the item exists in the checklistbox compared with the string we get then to make it checked.
Anyone can help with this ?
You can check a item of a checkListBox with the SetItemCheckState method by using the index of the item inside checkListBox.Items .
You can check if a string exists in checkListBox.Items with the IndexOf method which returns the index of the item that matches the string.
If checkListBox.Items contains the string the desired checkbox will be checked, if not IndexOf will return -1 and no checking will be done. Here is an example:
private void button1_Click(object sender, EventArgs e)
{
string fruit = "apple, oranges, kiwies";
string[] fruitArr = fruit.Split(',').Select(x=>x.Trim()).ToArray();
int index = 0;
foreach (var item in fruitArr)
{
index = checkedListBox1.Items.Cast<string>().ToList().IndexOf(item);
if (index > -1)
{
checkedListBox1.SetItemCheckState(index, CheckState.Checked);
}
}
}
Populating the checkListBox :
private void Form1_Load(object sender, EventArgs e)
{
List<string> fruitList = new List<string>() { "pineapple","banana","apple","oranges" };
foreach (var fruit in fruitList)
{
checkedListBox1.Items.Add(fruit);
}
}

combobox returning null value in c#

Here I created a for loop to list a range of numbers from 1 to 30 in the comboBox, but when I try to display the selected item from the combobox into a MessageBox it returns a null value. How can I get it to return the number selected from the comboBox? Here is my code:
string selectedNumber;
public Form1()
{
InitializeComponent();
for (int i = 1; i <= 30; i++)
{
string[] numbers= { i.ToString() };
comboBox1.Items.AddRange(numbers);
}
selectedNumber = comboBox1.SelectedText;
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show(selectedNumber);
}
}
Reason is clear that you have no text selected
You've to select any item in combobox first. To do so try any of the following
Set SelectedIndex to some valid index
Set SelectedItem to a valid item in combobox through code
Select an item in combobox by clicking it
Then use following code
MessageBox.Show(comboBox1.SelectedText); or
if(comboBox1.SelectedItem != null)//check for null since `SelectedItem` can be null when nothing selected
MessageBox.Show(comboBox1.SelectedItem.ToString());
Note: As #tim pointed in comments SelectedText approach won't work when DropDownStyle set to DropDownList. In that case you've to use SelectedItem approach
Here, with null check:
private void button1_Click(object sender, EventArgs e)
{
var selectedItem = comboBox1.SelectedItem ?? "";
MessageBox.Show(selectedItem.ToString());
}
As several have pointed out, there is nothing selected in the ComboBox when you assign SelectedText to selectedNumber. I would try two things:
First, don't call AddRange every time through the loop - build the array in the loop and then once the loop exits you can use AddRange. I would also use a List<string>:
List<string> numbers = new List<string>();
for (int i = 1; i <= 30; i++)
{
numbers.Add(i.ToString());
}
comboBox1.AddRange(numbers);
Secondly, in your button click event, show the selected text:
MessageBox.Show(comboBox1.SelectedText);
If comBox1's DropDownStyle is set to DropDownList, SelectedText will give an empty string. In that case, something like this might help:
MessageBox.Show(comboBox1.SelectedItem.ToString());
In reality, you'd probably want to handle the corresponding selection changed event for ComboBox as you'd probably want to do something with it in your program, but it looks like you're just trying some things out right now.
Edited To Add
Note that as Sriram said, SelectedItem can be null, so you'll want to check for that condition with either Sriram's or Przemyslaw's code if you're using SelectedItem instead of SelectedText.
Or, you can try this
for (int x = 0; x <= 30; x++)
comboBox1.Items.Add(x.ToString());
I find it a lot simpler

Get single listView SelectedItem

I have the MultiSelect property of the listView set to false and I'm trying to get a single listViewItem. But the available property is SelectedItems. I've been using the following code...
foreach (ListViewItem item in listView1.SelectedItems)
{
//do something with item.text or whatever
}
Because I know there will only be one item selected. What is the correct way of doing this?
Usually SelectedItems returns either a collection, an array or an IQueryable.
Either way you can access items via the index as with an array:
String text = listView1.SelectedItems[0].Text;
By the way, you can save an item you want to look at into a variable, and check its structure in the locals after setting a breakpoint.
I do this like that:
if (listView1.SelectedItems.Count > 0)
{
var item = listView1.SelectedItems[0];
//rest of your logic
}
Sometimes using only the line below throws me an Exception,
String text = listView1.SelectedItems[0].Text;
so I use this code below:
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
if (listView1.SelectedIndices.Count <= 0)
{
return;
}
int intselectedindex = listView1.SelectedIndices[0];
if (intselectedindex >= 0)
{
String text = listView1.Items[intselectedindex].Text;
//do something
//MessageBox.Show(listView1.Items[intselectedindex].Text);
}
}
If its just a natty little app with one or two ListViews I normally just create a little helper property:
private ListViewItem SelectedItem { get { return (listView1.SelectedItems.Count > 0 ? listView1.SelectedItems[0] : null); } }
If I have loads, then move it out to a helper class:
internal static class ListViewEx
{
internal static ListViewItem GetSelectedItem(this ListView listView1)
{
return (listView1.SelectedItems.Count > 0 ? listView1.SelectedItems[0] : null);
}
}
so:
ListViewItem item = lstFixtures.GetSelectedItem();
The ListView interface is a bit rubbish so I normally find the helper class grows quite quickly.
For a shopping cart situation here's what I recommend. I'm gonna break it down into it's simplest form.
Assuming we start with this(a list view with 2 colums, 2 buttons, and a label):
First things first, removing the items, to do that we'll enter our remove button:
private void button2_Click(object sender, EventArgs e)
{
listView1.Items.Remove(listView1.SelectedItems[0]);
label1.Text = updateCartTotal().ToString();
}
Now the second line is updating our labels total using the next function i'll post to addup all the total of column 2 in the listview:
private decimal updateCartTotal()
{
decimal runningTotal = 0;
foreach(ListViewItem l in listView1.Items)
{
runningTotal += Convert.ToDecimal(l.SubItems[1].Text);
}
return runningTotal;
}
You don't have to use decimal like I did, you can use float or int if you don't have decimals. So let's break it down. We use a for loop to total all the items in the column 2(SubItems[1].Text). Add that to a decimal we declared prior to the foreach loop to keep a total. If you want to do tax you can do something like:
return runningTotal * 1.15;
or whatever your tax rate is.
Long and short of it, using this function you can retotal your listview by just calling the function. You can change the labels text like I demo'd prior if that's what you're after.
None of the answers above, at least to me, show how to actually handle determining whether you have 1 item or multiple, and how to actually get the values out of your items in a generic way that doesn't depend on there actually only being one item, or multiple, so I'm throwing my hat in the ring.
This is quite easily and generically done by checking your count to see that you have at least one item, then doing a foreach loop on the .SelectedItems, casting each item as a DataRowView:
if (listView1.SelectedItems.Count > 0)
{
foreach (DataRowView drv in listView1.SelectedItems)
{
string firstColumn = drv.Row[0] != null ? drv.Row[0].ToString() : String.Empty;
string secondColumn = drv.Row[1] != null ? drv.Row[1].ToString() : String.Empty;
// ... do something with these values before they are replaced
// by the next run of the loop that will get the next row
}
}
This will work, whether you have 1 item or many. It's funny that MSDN says to use ListView.SelectedListViewItemCollection to capture listView1.SelectedItems and iterate through that, but I found that this gave an error in my WPF app: The type name 'SelectedListViewItemCollection' does not exist in type 'ListView'.
foreach (ListViewItem itemRow in taskShowListView.Items)
{
if (itemRow.Items[0].Checked == true)
{
int taskId = Convert.ToInt32(itemRow.SubItems[0].Text);
string taskDate = itemRow.SubItems[1].ToString();
string taskDescription = itemRow.SubItems[2].ToString();
}
}
If you want to select single listview item no mouse click over it try this.
private void timeTable_listView_MouseUp(object sender, MouseEventArgs e)
{
Point mousePos = timeTable_listView.PointToClient(Control.MousePosition);
ListViewHitTestInfo hitTest = timeTable_listView.HitTest(mousePos);
try
{
int columnIndex = hitTest.Item.SubItems.IndexOf(hitTest.SubItem);
edit_textBox.Text = timeTable_listView.SelectedItems[0].SubItems[columnIndex].Text;
}
catch(Exception)
{
}
}
This works for single as well as multi selection list:
foreach (ListViewItem item in listView1.SelectedItems)
{
int index = item.Index;
//index is now zero based index of selected item
}
On mouse click, I would do it like this:
public static string GetSelectedItem(ListView list)
{
foreach (ListViewItem item in list.Items)
{
if (item.Selected)
return item.Text;
}
return null;
}

how to change an item index in listview?

I have a listView and two buttons (UP , DOWN) and i want to move the selected item up or down.
I've thought about swapping between the selected item and the upper one.. but the code i tried .. doesn't make sense because index is readonly.
also mines or sum doesn't owrk .. i can't mess with index at all.
private void btnDown_Click(object sender, EventArgs e)
{
listView1.SelectedItems[0].Index--; // It's ReadOnly.
}
So .. how do i let the user the ability to change a ListViewItem index like how VB let us to change these item index [like in the pic]
thanks in advance ...
You have to remove the selected item first, then re-add it at the new position.
E.g to move the item up one position:
var currentIndex = listView1.SelectedItems[0].Index;
var item = listView1.Items[index];
if (currentIndex > 0)
{
listView1.Items.RemoveAt(currentIndex);
listView1.Items.Insert(currentIndex-1, item);
}
Following is an improvement to M4N answer to handle the re order of an item in the top of the list and make it in the bottom of the list
int currentIndex = listView1.SelectedItems[0].Index;
ListViewItem item = listView1.Items[currentIndex];
if (currentIndex > 0)
{
listView1.Items.RemoveAt(currentIndex);
listView1.Items.Insert(currentIndex - 1, item);
}
else
{
/*If the item is the top item make it the last*/
listView1.Items.RemoveAt(currentIndex);
listView1.Items.Insert(listView1.Items.Count, item);
}
In case of observable collections you are also able to call: .Move(currentindex, newindex);
MSDN

Categories