Getting the old selected index in Winform's Combo box - c#

I have a combo box (winform). This combo box has some items (eg. 1,2,3,4).
Now, when I change the selection within this combo, I wish to know the old index and the new index.
How do I get this?
Possible approaches that I wish to AVOID.
Add an enter event, cache the current index and then on selection index change get the new index.
Using the selected text/selected item property received by the sender of the event.
What I ideally want:
In the event args that are received, I want something like:
e.OldIndex;
e.newIndex;
Right now the event args which are received in the SelectionIndex Change event are totally useless.
I don't want to use more than one event.
If C#, does not offer this, can I have my event which passes the old index and new index as event args?

Seems like this is a possible duplicate
ComboBox SelectedIndexChanged event: how to get the previously selected index?
There is nothing built in, you will need to listen for this event and keep track in a class variable.
But this answer seems to suggest a sensible way of extending the combobox to keep track of the previous index
https://stackoverflow.com/a/425323/81053

1-Make a List of integers
2-Bind a Button to switch to previous Screen (button Name "prevB")
3-change the ComboBox Index as Per described in the code
//initilize List and put current selected index in it
List<int> previousScreen = new List<int>();
previousScreen.Add(RegionComboBox.SelectedIndex);
//Button Event
private void prevB_Click(object sender, EventArgs e)
{
if (previousScreen.Count >= 2)
{
RegionComboBox.SelectedIndex = previousScreen[previousScreen.Count - 2];
}
}

You will need to replace the ComboBox with the following control:
public class AdvancedComboBox : ComboBox
{
private int myPreviouslySelectedIndex = -1;
private int myLocalSelectedIndex = -1;
public int PreviouslySelectedIndex { get { return myPreviouslySelectedIndex; } }
protected override void OnSelectedIndexChanged(EventArgs e)
{
myPreviouslySelectedIndex = myLocalSelectedIndex;
myLocalSelectedIndex = SelectedIndex;
base.OnSelectedIndexChanged(e);
}
}
Now you can get the PreviouslySelectedIndex property.

You can use YourComboBox.Tag (or other unused string/int property) to store old selected index...

I use such pair
comboBox.SelectedItem new item
comboBox.SelectionBoxItem old item

Related

Index of last checked change checkbox from list of them

How to get the index of last checkbox where checked change from list of them? If someone asks, no, I can't use CheckedListBox control for this project.
I have
List<CheckBox> checkboxes = new List<CheckBox>();
and then I adding some checkboxes to this list
What I want to do is to get the index of checkbox which recently checked state changed
so...
every checkbox from this list have this same handler for the CheckedChanged event
and then in this void I want to get index of this checkbox which trigger this event for example for this code
public void checked_change(object sender, EventArgs e)
{
int x = // here i want this index
if (checkboxes[x].Checked==true)
{
}
}
The object sender argument to the event-handler contains the 'recently changed' CheckBox.
You would need to cast the object back to the CheckBox type and find it's index in the list using List.IndexOf.
int x = checkboxes.IndexOf((CheckBox)sender);
Make sure you only hook CheckBoxes onto the event-handler or perform a safe conversion

Filter items in a ListView in real time

My program generates ListView full of information. I type into a text box a name that might match one of the item names in the ListView. I want this typed name to weed out the names from the ListView that don't match.
For example, if I type in "abc", names like "uvw" and "xyz" wouldn't show up anymore, but "abc" and "abcde" would still show up in the list view.
The end goal is to be able to check the checkboxes next to the names I want, and search for more names, eventually selecting several, without resetting the checkboxes.
Right now I click a button and the ListView is populated:
private void button1_Click(object sender, EventArgs e)
{
List<string> myList = getList();
foreach(string s in myList)
{
listView1.Items.Add(s);
}
}
getList() just returns a List<string> of all the names I want.
I can't figure out how to make the ListView update in real time when I type in my text box. I'm able to update it with a button click via repopulating the ListView based on looping through the List, and checking each name, but that's not what I want. It also doesn't retain checked check boxes, as it's a newly generated list each time.
I read about a "text change listener", but I'm not sure that's what I should be using here...
With filtering you need some way of remembering which ListViewItems are selected, so instead of inserting all your ListViewItems into your listview you want to instantiate them in a master list. Then attach a TextChanged event handler to your text box and when the text changes you display the items.
List<ListViewItem> masterlist;
public Form1()
{
InitializeComponent();
masterlist = new List<ListViewItem>();
}
private void button1_Click(object sender, EventArgs e)
{
// Populate the masterlist
masterlist.Clear();
foreach(string s in getList())
{
masterlist.Items.Add(new ListViewItem(s));
}
// Display the items in the listview
DisplayItems();
}
private void DisplayItems()
{
listView1.Items.Clear();
// This filters and adds your filtered items to listView1
foreach(ListViewItem item in masterlist.Where(lvi => lvi.Text.ToLower().Contains(textBox1.Text.ToLower().Trim())))
{
listView1.Items.Add(item);
}
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
// Re-display the items when the filter changes
DisplayItems();
}
As you're dealing directly with ListViewItems in your masterlist they will retain their checked state when swapped in and out of listView1.
I have assumed that your filter textbox is called textBox1.
If you want to go for a full C# solution (rather than using any Javascript), as much as it pains me, I would suggest using an UpdatePanel.
Put your ListBox inside they the <ContentTemplate> section of the <UpdatePanel> then add an <asp:AsyncPostBackTrigger> with the ControlID set to that of your textbox. Make sure that the UpdateMode property of the UpdatePanel is set to "Conditional".
On your TextBox you will also have to set the AutoPostBack property to true. On the TextBox itself you will have to create a TextChanged event handler, then in your code behind (.cs file) you will have the logic for your TextChanged handler which will filter the list then set the new value for your ListBox.
UpdatePanels are ok for simply scenarios, but you can very easily get yourself into trouble by mis-using them.

c# confirm each combobox has a unique value selected

I have a winform with a group of comboboxes, all of the comboboxes with the same list items in them.
I need a way to confirm that when the user is done selecting a value in each box that they only selected each list value once.
Ex:
cbox1 cbox2 cbox 3
Item A Item B Item A (this needs to flag an error since Item A is already selected in cbox1)
I was thinking trying to use the selectedvaluecommited action (as after i populate the list I change the selected index to -1 so they all show "empty" to start) but the loop to make it work seems to be eluding me.
background: this is choosing fields to build a spreadsheet and the user needs to choose the field order.
You can do it like this (quick and dirty):
Add SelectedIndexChanged handler for all three comboboxes (in Form_Load in example)
comboBox1.SelectedIndexChanged += CheckComboBoxes;
comboBox2.SelectedIndexChanged += CheckComboBoxes;
comboBox3.SelectedIndexChanged += CheckComboBoxes;
in CheckComboBoxes method do your checking:
private void CheckComboBoxes(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex == comboBox2.SelectedIndex ||
comboBox1.SelectedIndex == comboBox3.SelectedIndex ||
comboBox2.SelectedIndex == comboBox3.SelectedIndex)
MessageBox.Show("comboboxes are not unique");
}
EDIT:
this is approach when having n comboboxes. Put all items into list, select distinct values and compare that distinct count with items count... Something like this:
private void CheckComboBoxes(object sender, EventArgs e)
{
List<string> comboValues = new List<string>();
foreach (Control c in this.Controls)
{
if (c is ComboBox && !string.IsNullOrEmpty((c as ComboBox).SelectedItem.ToString()))
comboValues.Add((c as ComboBox).SelectedItem.ToString());
}
if (comboValues.Distinct().ToList().Count < comboValues.Count)
MessageBox.Show("not all combos are unique");
}
Here's an approach you can take.
To make the affected comboboxes easy to distinguish, put them all in a GroupBox container.
Write a validation method for your group box.
Subscribe to the group box Validating event by attaching it to your validation method.
In your validation method, loop through all the ComboBox controls in the group box and check if there are any duplicates, and issue an error if so.
For example, assuming the group box is called groupBox1:
private void GroupBox1_Validating(object sender, CancelEventArgs e)
{
base.OnValidating(e);
var selectedIndices = groupBox1.Controls.OfType<ComboBox>().Select(item => item.SelectedIndex);
var anyDuplicates = selectedIndices.GroupBy(x => x).Any(x => x.Count() > 1);
if (!anyDuplicates)
return;
MessageBox.Show("There are duplicates!");
e.Cancel = true;
}
And subscribe to the group box Validating event in the Form1 constructor:
public Form1()
{
InitializeComponent();
groupBox1.Validating += GroupBox1_Validating;
}
Sometimes when validating like this, you need to prevent the validation logic from executing if the user clicks the Cancel button. You're supposed to be able to set the CausesValidation property of the Cancel button to false to prevent this, but I find that it doesn't work for me.
Instead, I just use a bool cancelling field which I set to true in the Cancel button handler:
private void cancelButton_Click(object sender, EventArgs e)
{
cancelling = true;
this.Close();
}
bool cancelling;
And then add the following to the start of GroupBox1_Validating():
if (cancelling)
return;
If it is possible to have different UI design then my suggestion goes as under:
Alternative UI Design - A
Create One ListBox ListFieldsOriginal and populate
Create Second ListBox ListUserSelection, keep it empty initially
Provide buttons as under:
Button '>' means add currently selected item from ListFieldsOrginial to ListUserSelection at end; and remove that item from ListFieldsOriginal
Button '<' means remove currenly selected item from lstUserSelection; and add that item back to ListFieldsOriginal (of course at end)
NOTE: If adding item back to ListFieldsOriginal is your requirement then extra coding is required to find its appropriate index in the ListFieldsOriginal.
Alternative UI Design - B
Create One CheckedListBox ListFieldsOriginal and populate
Create one ListBox ListUserSelection, keep it empty initially
Define ItemCheck event handler for ListFieldsOriginal to add/remove items to/from ListUserSelected.
if (e.CurrentValue==CheckState.Unchecked)
{
string item = ListFieldsOriginal.Items[item];
ListUserSelection.Items.Add(item);
}
else
{
string item = ListFieldsOriginal.Items[item];
ListUserSelection.Items.Remove(item);
}

Behaviour of combo-boxes items, will they perform their actions if a previous variable defines what combo-box i'm in?

It's the following, i have 1 combo-box with item1 and item2
private void ComboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (ComboBox1.SelectedItem == "item1")
{
variableA = 0;
}
else if (ComboBox1.SelectedItem == "item2")
{
variableA = 1;
}
}
and early in the program i have another variable that sets what item the combobox is in, for example
int variablecomboboxitem = 1;
if (variablecomboboxitem == 1) {ComboBox1.SelectedItem = "item1"}
else if (variablecomboboxitem == 2 ){ComboBox1.SelectedItem = "item2"}
but, for diverse reasons i might need to start with variablecomboboxitem = 2;
the question is.. when i set the variablecomboboxitem = 1 early on the program, the item1 will show up in the combobox, but will it load variableA = 0??? or will he just set the item on the combobox???
if he doesn't load the variableA value, how can i make it so that he performs the actions after the combo-box item?
If I'm understanding the question properly, you're essentially asking if the SelectedIndexChanged event will be raised if you set the selected index programmatically.
The answer is yes. Setting the selected index of a combo box programmatically (e.g. by modifying the SelectedIndex property in the constructor) will raise the SelectedIndexChanged event, and therefore cause the code in your event handlers to be executed. If you set the selected index to 1, variableA will be set to 0. If you set the selected index to 2, variableA will be set to 1. Or whatever logic your code in the event handler method implements.
Of course, the SelectedIndexChanged event is only raised when the selected index is changed. If you set the selected item to "item1" in the constructor, and then the user re-selects "item1", the event won't be fired again. But that's probably what you want. The value of variableA wouldn't change anyway by your current logic.
yes, variableA=0 will be the value.
I am not illustrating this anymore. Cody Gray's explanation is great!

How to avoid rising ComboBox SelectionChanged event when doing it in codebehind in WPF?

I have a function that will change a combo box selected index, so combobox_selectionchanged event will rise automatically,but the handler of this event call my function again,so the function will be called twice!!
IS there any way to prevent rising selection_changed event in function below?
private void Refresh_Window()
{
Monthes_ComboBox.SelectedIndex = DM.Month - 1;
}
I wanted to avoid a long description about my problem, so I just asked the question. I'm designing a calendar, the combo_box contains monthes of a year, but there are two buttons that will go to nextmonth or previous month,so I have to change the combo_box index by code, I create a function and I called it in form_load and combobox_Selection_changed and button_click Can I design it in a better way? and Refresh_window doesn't just change the combobox_selectedindex, it changes all Labels and TextBlocks in form, so I just wanted all changes to be done by Refresh_window
private bool _refreshCalled = false;
private void Refresh_Window()
{
_refreshCalled = true;
try
{
....
Monthes_ComboBox.SelectedIndex = DM.Month - 1;
....
}
finally
{
_refreshCalled = false;
}
}
private void OnComboBoxSelectedChanged(object sender, EventArgs e)
{
...
if (!_refreshCalled)
{
Refresh_Window();
}
...
}
if you use a function to raise an event and you call that same function from the event handler, to what I understand this is at minimum badly designer and not optimal.
in general with combo boxes you can simply assign the SelectedValue and the control will select the item with that value then the selected index will change to the index of such item, you would not really need to set the selected index directly...
if you really want to work by index anyway you are free to do but I would avoid this spaghetti coding having a method which change the selected index if the same method is also called by the event handler attached to the event fired...
There are a couple of good ways to do this:
Set a variable that indicates the selected index is changing in the combobox (you'll need to derive from the built-in ComboBox class). If selected index changes again from deeper in the call stack, the variable will still be set and you can read it before trying to change the selected index again.
Similarly, if the call stack involves handlers attached to the combobox, you can override OnSelectedIndexChanged and not perform any logic if this is the second time the selected index has changed.

Categories

Resources