C# - Add/Remove with ListBoxes - winforms

Right now I have 3 RichTextBox(es) with text in them. I am taking this text from these boxes and splitting each line and adding each separate line to its corresponding ListBox. Here is my code for that:
private void listFormatHelper()
{
// Splits the lines in the rich text boxes
var listOneLines = placementOneRichTextBox.Text.Split('\n');
var listTwoLines = placementTwoRichTextBox.Text.Split('\n');
var listUserLines = userDefinedRichTextBox.Text.Split('\n');
// Resest the text in the listboxes
placementOneListBox.ResetText();
placementTwoListBox.ResetText();
userDefinedListBox.ResetText();
// Set the selection mode to multiple and extended.
placementOneListBox.SelectionMode = SelectionMode.MultiExtended;
placementTwoListBox.SelectionMode = SelectionMode.MultiExtended;
userDefinedListBox.SelectionMode = SelectionMode.MultiExtended;
// Shutdown the painting of the ListBox as items are added.
placementOneListBox.BeginUpdate();
placementTwoListBox.BeginUpdate();
userDefinedListBox.BeginUpdate();
// Display the items in the listbox.
placementOneListBox.DataSource = listOneLines;
placementTwoListBox.DataSource = listTwoLines;
userDefinedListBox.DataSource = listUserLines;
// Allow the ListBox to repaint and display the new items.
placementOneListBox.EndUpdate();
placementTwoListBox.EndUpdate();
userDefinedListBox.EndUpdate();
}
After the above code, each ListBox has the specified data in it on separate lines. However, what I am trying to do is add buttons buttons, that when clicked move the selected list item to the specified ListBox.
VISUAL LAYOUT OF LISTBOXES:
placementOneListBox userDefinedListBox placementTwoListBox
| | | | | |
| | | | | |
| | | | | |
| | | | | |
|_________________| |_________________| |_________________|
So, what I am trying to do is have a button that says "move right" or "move left" and it takes the currently selected item (preferably items for multiselection) and moves it to either the left or to the right ListBox. However, for the placementOneListBox the "move left" button will not work and for the placementTwoListBox the "move right" button will not work. I tried this way below (which did not work):
private void placementOneMoveRightButton_Click(object sender, EventArgs e)
{
var currentItemText = placementOneListBox.SelectedValue.ToString();
var currentItemIndex = placementOneListBox.SelectedIndex;
userDefinedListBox.Items.Add(currentItemText);
placementOneListBox.Items.Remove(currentItemIndex);
placementOneListBox.Items.RemoveAt(placementOneListBox.Items.IndexOf(placementOneListBox.SelectedItem));
}
I also tried this way (which also did not work):
private void placementOneMoveRightButton_Click(object sender, EventArgs e)
{
string str;
str = placementOneListBox.SelectedItems.ToString();
placementOneListBox.Items.Remove(placementOneListBox.SelectedItems);
userDefinedListBox.Items.Add(str);
}
THE REASON WHY THEY DO NOT WORK:
Whenever I am running the program and I click the "move right" button (for either code cases above) I get the following error:
"Items collection cannot be modified when the DataSource property is set."
QUESTIONS
Does anyone know what I am doing wrong in this?
Can someone show/explain what is happening with the "DataSource property" and how I can get around it?

You are trying to modify the dataset while it is bound to the listbox. What you need to do instead is recreate the dataset and then bind that new dataset to the listbox.
Sorry Colton, had a meeting at work.
I am not sure what kind of data you are working with, but here is an example of removing a name and adding a name to a ListBox:
private class Names
{
public string Name { get; set; }
public Names(string name)
{
Name = name;
}
}
private void Form1_Load(object sender, EventArgs e) // Form Load Event
{
List<Names> names = new List<Names>();
names.Add(new Names("John"));
names.Add(new Names("Suzy"));
names.Add(new Names("Mary"));
names.Add(new Names("Steve"));
listBox1.DataSource = names;
listBox1.DisplayMember = "Name";
listBox1.ValueMember = "Name";
}
private void button1_Click(object sender, EventArgs e)
{
List<Names> names = new List<Names>();
foreach (var item in listBox1.Items)
{
Names name = (Names)item;
if (name.Name.Equals("Mary")) // Remove Mary
continue;
names.Add(name);
}
names.Add(new Names("Joe")); // Add Joe
listBox1.DataSource = names;
listBox1.DisplayMember = "Name";
listBox1.ValueMember = "Name";
}
So what I'm doing is in the Form Load event, I'm populating my listbox with fresh names and setting the datasource to my List object. When the button is clicked, I am creating a NEW List and populating with the same names except for poor Mary. She's out of the list. I then Add Joe to the list and then set the datasource again. The important thing to take away from this is that once you have binded a data source to a listbox, you CANNOT modify that data source in any way. You must create a new datasource and then rebind to the new source. Does this make more sense now?

refer following article at code project : How to Move List Box Items to another List Box in C#.
also you can look at so quetion : how-to-remove-selected-items-from-listbox-when-a-datasource-is-assigned-to-it-in

Does this work:
private void placementOneMoveRightButton_Click(object sender, EventArgs e)
{
for(int i = 0; i < placementOneListBox.SelectedItems.Count(); i++)
{
var item = placementOneListBox.Items[i];
if(item.Selected)
{
placementOneListBox.Items.RemoveAt(i);
userDefinedListBox.Items.Add(item);
}
}
}

Related

How do I set values for the entries in a Windows Forms ComboBox?

I want to have a drop down list with 12 choices.
I found that ComboBox is what I need (if there is a better control kindly tell me).
I dragged and drop a combo box into a panel using VS2012 and then clicked on the left arrow that appears on the combo box. The following wizard shows:
As you can see, I am just able to type the name of the choice but not the value of it.
My question is how to get the value of these choices?
What I have tried
I built an array with the same length as the choices, so when the user selects any choice, I get the position of that choice and get the value from that array.
Is there a better way?
You need to use a datatable and then select the value from that.
eg)
DataTable dt = new DataTable();
dt.Columns.Add("ID", typeof(int));
dt.Columns.Add("Description", typeof(string));
dt.Load(reader);
//Setting Values
combobox.ValueMember = "ID";
combobox.DisplayMember = "Description";
combobox.SelectedValue = "ID";
combobox.DataSource = dt;
You can then populate your datatable using:
dt.Rows.Add("1","ComboxDisplay");
Here, the DisplayMember(The dropdown list items) are the Descriptions and the Value is the ID.
You need to include a 'SelectedIndexChanged' Event on your combobox (If using VS then double click the control in Design Mode) to get the new values. Something like:
private void ComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
int ID = Combobox.ValueMember;
string Description = ComboBox.DisplayMember.ToString();
}
You can then use the variables in the rest of your code.
You cannot use the wizard to store values and text. To store DisplayText/Value pair the combobox needs to be connected to some data.
public class ComboboxItem
{
public string DisplayText { get; set; }
public int Value { get; set; }
}
There are two properties on the combobox - DisplayMember and ValueMember. We use these to tell the combobox that - show whats in DisplayMember and the actual value is in ValueMember.
private void DataBind()
{
comboBox1.DisplayMember = "DisplayText";
comboBox1.ValueMember = "Value";
ComboboxItem item = new ComboboxItem();
item.DisplayText = "Item1";
item.Value = 1;
comboBox1.Items.Add(item);
}
To get the value -
int selectedValue = (int)comboBox1.SelectedValue;

Windows Form Combobox.Items.Clear() leaves empty slots

I am working on a Windows Form that has multiple comboboxes. Depending on what is chosen in the first combobox determines what items are filled into the second combobox. The issue I am running into is if I choose ChoiceA in ComboBox1, ComboBox2 is clear()ed, then is filled with ChoiceX, ChoiceY, and ChoiceZ. I then choose ChoiceB in ComboBox1, ComboBox2 is clear()ed, but there are no choices to add to ComboBox2, so it should remain empty. The issue is, after choosing ChoiceB, there's a big white box with three empty slots in ComboBox2. So, basically, however many items are cleared N, that's how many empty slots show up after choosing ChoiceB.
This might be a tad confusing, I hope I explained it well enough.
-- EDIT Adding Code, hope it helps clear things up. BTW, mainItemInfo is another "viewmodel" type class. It interfaces back into the form to make updates.
private void cmbType_SelectedIndexChanged(object sender, EventArgs e)
{
DropDownItem item = (DropDownItem)cmbType.SelectedItem;
if (!String.IsNullOrWhiteSpace(item.Text))
{
cmbBrand.Enabled = true;
btnAddBrand.Enabled = true;
mainItemInfo.FillBrands(new Dictionary<string, string> { { "Type", item.Text } });
mainItemInfo.SyncBrands(this);
}
}
public void FillBrands(Dictionary<string, string> columnsWhere)
{
// Clear list
Brands.Clear();
// Get data
StorageData storage = new StorageData(File.ReadAllLines(ItemsFilePath));
// Fill Brands
foreach (string type in storage.GetDistinctWhere(columnsWhere, "Brand"))
{
Brands.Add(type, new DropDownItem(type, type));
}
}
public void SyncBrands(IPopupItemInfo form)
{
form.ClearcmbBrand();
var brands = from brand in Brands.Keys
orderby Brands[brand].Text ascending
select brand;
foreach (var brand in brands)
{
form.AddTocmbBrand(Brands[brand]);
}
}
public void AddTocmbBrand(DropDownItem brand)
{
cmbBrand.Items.Add(brand);
}
public void ClearcmbBrand()
{
cmbBrand.Items.Clear();
}
Simply, you can add an item then clear the combobox again:
cmbBrand.Items.Clear();
cmbBrand.Items.Add(DBNull.Value);
cmbBrand.Items.Clear();
You should able to set the datasource of listbox2 to null to clear it, then set it again with the new data.
So, in pseudo-code, something like:
ItemSelectedInListBox1()
{
List futureListbox2Items = LoadOptionsBaseOnSelectedItem(item)
Listbox2.Datasource = null
Listbox2.Datasource = futureListBox2Items
}
That should refresh the list of items displayed in Listbox2 with no white spaces.
I was able to fix the extra space. I changed the Add and Clear methods to:
public void AddTocmbModel(DropDownItem model)
{
cmbModel.Items.Add(model);
cmbModel.DropDownHeight = cmbModel.ItemHeight * (cmbModel.Items.Count + 1);
}
public void ClearcmbModel()
{
cmbModel.Items.Clear();
cmbModel.DropDownHeight = cmbModel.ItemHeight;
}

How to find matching words in Text Box and Datagrid when VirtualizingStackPanel.IsVirtualizing="true"?

I have Datagrid and Text Box in my Form. Datagrid is showing me existing items in my stock. I use Text Box to search and set focus to that row which is matching with my Text Box. Now it is working fine when VirtualizingStackPanel.IsVirtualizing="false" but it is very slow and getting a lot RAM resource.
Here is my code for this.
public IEnumerable<Microsoft.Windows.Controls.DataGridRow> GetDataGridRows(Microsoft.Windows.Controls.DataGrid grid)
{
var itemsSource = grid.ItemsSource as IEnumerable;
if (null == itemsSource) yield return null;
foreach (var item in itemsSource)
{
var row = grid.ItemContainerGenerator.ContainerFromItem(item) as Microsoft.Windows.Controls.DataGridRow;
if (null != row) yield return row;
}
}
private void SearchBoxDataGrid_TextChanged(object sender, TextChangedEventArgs e)
{
var row = GetDataGridRows(AssortDataGrid);
/// go through each row in the datagrid
foreach (Microsoft.Windows.Controls.DataGridRow r in row)
{
DataRowView rv = (DataRowView)r.Item;
// Get the state of what's in column 1 of the current row (in my case a string)
string t = rv.Row["Ассортимент"].ToString().ToLower();
if (t.StartsWith(SearchBoxDataGrid.Text.ToLower()))
{
AssortDataGrid.SelectedIndex = r.GetIndex();
AssortDataGrid.ScrollIntoView(AssortDataGrid.SelectedItem);
break;
}
}
}
What I want is to make it VirtualizingStackPanel.IsVirtualizing="true" but in this case my method is not working. I know why it is not working, my code will work only for showing part of Datagrid.
What do you recommend? How to fix this issue? Any idea will be appreciated. If you give any working code it will be fantastic. I hope I could explain my problem.
Virtualization means that WPF will reuse the UI components, and simply replace the DataContext behind the components.
For example, if your Grid has 1000 items and only 10 are visible, it will only render around 14 UI items (extra items for scroll buffer), and scrolling simply replaces the DataContext behind these UI items instead of creating new UI elements for every item. If you didn't use Virtualization, it would create all 1000 UI items.
For your Search to work with Virutalization, you need to loop through the DataContext (DataGrid.Items) instead of through the UI components. This can either be done in the code-behind, or if you're using MVVM you can handle the SeachCommand in your ViewModel.
I did a little coding and make it work. If anyone needs it in future please, use it.
Firstly I am creating List of Products
List<string> ProductList;
Then on Load Method I list all my products to my Product List.
SqlCommand commProc2 = new SqlCommand("SELECT dbo.fGetProductNameFromId(ProductID) as ProductName from Assortment order by ProductName desc", MainWindow.conn);
string str2;
SqlDataReader dr2 = commProc2.ExecuteReader();
ProductList = new List<string>();
try
{
if (dr2.HasRows)
{
while (dr2.Read())
{
str2 = (string)dr2["ProductName"];
ProductList.Insert(0, str2.ToLower ());
}
}
}
catch (Exception ex)
{
MessageBox.Show("An error occured while trying to fetch data\n" + ex.Message);
}
dr2.Close();
dr2.Dispose();
After that I did some changes in SearchBoxDataGrid_TextChanged
private void SearchBoxDataGrid_TextChanged(object sender, TextChangedEventArgs e)
{
int pos = 0;
string typedString = SearchBoxDataGrid.Text.ToLower();
foreach (string item in ProductList)
{
if (!string.IsNullOrEmpty(SearchBoxDataGrid.Text))
{
if (item.StartsWith(typedString))
{
pos = ProductList.IndexOf(item);
AssortDataGrid.SelectedIndex = pos;
AssortDataGrid.ScrollIntoView(AssortDataGrid.SelectedItem);
break;
}
}
}
}
Now it works when VirtualizingStackPanel.IsVirtualizing="true".
That is all.

Under SelectionChanged read out the underlying data from a List

Im busy with my app and i walked in some problems when i click on a photo in my listbox PhotoFeed.
I got 1 List<> with in it the strings UrlTumb and UrlFull.
I got 1 ListBox with in it a WrapPanel filled with images wich i set the Image.Source from my UrlTumb.
What my problem is when i click on a photo in my listbox i want to navigate to a new page and display there the original image (UrlFull) now i can only get my UrlTumb from my Image.Source but i want my UrlFull which is stored in the List. Now is my question how do i obtain the UrlFull. So how can i back trace which item i clicked and get the UrlFull from that item so i can send it with my NavigationService.Navigate
I can do it on an dirty way and create an invisible textblock besides the image in my ListBox and put the UrlFull in there but i would like to do it in a proper way
So what do i place in the ????? spot in this line
NavigationService.Navigate(new Uri("/PhotoInfo.xaml?urlfull={0}", ????? , UriKind.Relative));
Greetings Cn
There are multiple options:
Use selected item's index listBox.SelectedIndex to get the index
of the selected property which will correspond to the index in your
source (it might not if you filter the collection using collection
source, but I think that is not the case)
Use selected item listBox.SelectedItem this will return the
SelectedItem which will contain your object. (Note, that if your
selection mode set to multiple, this will return only the firstly
selected item)
Use SelectemItems. It will allow you to get an array of selected
items (Note: this should be normally used only when your list's
selection mode is set to multiple)
Use SelectedValue, which will contain the value of the SelectedItem
(this will save you and extra step.
Use arguments of the Selection changed event AddedItems.
Bellow is the code snippet of 3 options above. x, y, z will all be your selected names (e.g. "Mike")
XAML:
<ListBox x:Name="lb"
ItemsSource="{Binding Names}"
SelectionChanged="NameChanged" />
Code behind:
public class Person
{
public string Name { get; set; }
public override string ToString()
{
return Name;
}
}
private List<Person> people = new List<Person>
{
new Person{Name = "Lewis"},
new Person{Name = "Peter"},
new Person{Name = "Brian"}
};
public List<Person> People
{
get
{
return this.people;
}
set
{
this.people = value;
}
}
private void NameChanged(object sender, SelectionChangedEventArgs e)
{
var x = this.people[lb.SelectedIndex];
var y = lb.SelectedItem;
var z = lb.SelectedItems[0];
var h = lb.SelectedValue;
var u = e.AddedItems[0];
var person = e.AddedItems[0] as Person;
if (person != null)
{
var result = person.Name;
}
}
For the differences between SelectedValue and SelectedItem refer here SelectedItem vs SelectedValue

WinForms ComboBox: text vs. selectedtext

In my WinForms / C# application, I can choose either Combobox.Text or Combobox.SelectedText to return the string value of what's been selected. What's the difference, and when would I choose one over the other?
SelectedText is what's highlighted. Depending on the DropDownStyle property, users can select a part of the visible text.
For example, if the options are:
Democrat
Republican
Independent
Other
A user can select the letters "Dem" in Democrat - this would be the SelectedText. This works with the ComboBoxStyle.Simple or ComboBoxStyle.DropDown, but NOT with ComboBoxStyle.DropDownList, since the third style does not allow selecting a portion of the visible item (or adding new items).
http://msdn.microsoft.com/en-us/library/system.windows.forms.combobox.selectedtext.aspx
http://msdn.microsoft.com/en-us/library/system.windows.forms.comboboxstyle.aspx
However, using the Text property, you can pre-select an option (by setting the Text to "Other", for example, you could select the last item.)
http://msdn.microsoft.com/en-us/library/system.windows.forms.combobox.text.aspx
I find it easier to see the difference using a text box:
private void Form1_Load(object sender, EventArgs e)
{
textBox1.Text = "Text in combo box 1";
textBox2.Text = "Text in combo box 2";
button1.Focus();
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show(textBox2.SelectedText);
}
In textbox2, select part of the text and click the button.
I've used this before for primitive spell checkers, when you only want to highlight part of the textbox (not the whole value)
Try this one. It helps when the DropDownStyle property is set to DropDownList.
public string GetProdName(int prodID)
{
string s = "";
try
{
ds = new DataSet();
ds = cmng.GetDataSet("Select ProductName From Product where ProductID=" + prodID + "");
if (cmng.DSNullCheck(ds) && cmng.DSRowCheck(ds))
{
s = ds.Tables[0].Rows[0][0].ToString();
}
}
catch {
}
return s;
}
In the click event:
lblProduct.Text = GetProdName((int)ddlProduct.SelectedValue);
If you want to read an item text which is in a combobox, you can use [comboboxname].SelectedItem.ToString().
If you want to read an item value, use [comboboxname].SelectedValue.

Resources