I have a ListBox in winforms Application, now the business logic demands me to fire one function if an item in the List Box is Selected and fire another if an item in the List Box is Deselected.
But the way I see it none of the Events Listed in VS is giving that power of Execution. I do see Events like
SelectedIndexChanged(object sender, EventArgs e)
and
SelectedValueChanged(object sender, EventArgs e)
But both these event fires if there is a change in the selection of the ListBox. But it doesn't specify if an item was selected or deselected which raised the event.
Any suggestion on this would be very helpful.
I even found the following link on MSDN
https://msdn.microsoft.com/en-us/library/system.windows.controls.listboxitem.unselected%28v=vs.110%29.aspx
But I am not sure how to apply the same in this situation.
Posting the Tedious Solution. Might help some1 in the future to Copy Paste.
public static int ListCount;
private void listBoxPackService_SelectedIndexChanged(object sender, EventArgs e)
{
int CurrCount;
ListBox.SelectedObjectCollection col = listBoxPackService.SelectedItems;
CurrCount = col.Count;
if (CurrCount > ListCount)
{
//Item Selected
}
else
{
//Item DeSelected
if(CurrCount == 0)
{
//All Items Were Deselected
}
}
ListCount = CurrCount;
}
On load of the ListBox
ListCount = 0
rename the Controls as per your requirement.
I am still open for a better solution :)
Related
Basically, I have a ListView of items. When one is selected, a text box comes into view on the right to display more details of that item (takes a little time for the item data to be grabbed). The behavior I was going for was to hide this text box on right when all items get unselected.
private void listView1_SelectedIndexChanged(object sender, EventArgs e) {
// should only be 1 item selected, it's not a multi-select listview
ListView.SelectedListViewItemCollection collection = this.listView1.SelectedItems;
if (collection.Count == 0) {
this.label2.Visible = false;
}
foreach (ListViewItem item in collection) {
this.label2.Visible = true;
getSideInformation(item.Text);
}
}
I noticed a flicker of the box, when I am simply selecting another item. I did some digging by changing my code to:
private void listView1_SelectedIndexChanged(object sender, EventArgs e) {
// should only be 1 item selected, it's not a multi-select listview
ListView.SelectedListViewItemCollection collection = this.listView1.SelectedItems;
if (collection.Count == 0) {
this.label2.Text = "Unselected all!"
}
foreach (ListViewItem item in collection) {
getSideInformation(item.Text);
}
}
Basically, I no longer hide the box, but just change the text if it's a selection change event with 0 items selected. What I found out is that this event actually fires TWICE for a simple select another item (once with 0 items, and a second time with the new items selected). So my box will always display "Unselected all!" while it's loading up any side information if I had previously selected an item and was changing to another item.
Is there any way to differentiate an actual event firing of all items unselected versus that initial firing of 0 items for the selecting another item case?
You can register to ListView's ItemSelectionChangedEvent instead.
this.listView1.ItemSelectionChanged += this.HandleOnListViewItemSelectionChanged;
private void HandleOnListViewItemSelectionChanged(Object sender, ListViewItemSelectionChangedEventArgs e)
{
if (e.IsSelected)
{
this.detailsLabel.Text = this.GetDetails(e.Item);
}
else
{
this.detailsLabel.Text = String.Empty;
}
}
In any control where you can select multiple items, SelectedIndexChanged event fires twice. One, to remove the deselected item and then to add selected item. When you click first time, selected items collection is null and hence it fired once. Next time it will fire twice.
The best solution I've found is to temporarily set an event handler to Application.Idle and do your checking from there, like so:
bool handled;
private void listView1_SelectedIndexChanged(object sender, EventArgs e) {
if (!handled)
{ handled = true;
Application.Idle += SelectionChangeDone; }
}
private void SelectionChangeDone(object sender, EventArgs e) {
Application.Idle -= SelectionChangeDone;
handled = false;
ListView.SelectedListViewItemCollection collection = this.listView1.SelectedItems;
if (collection.Count == 0)
this.label2.Text = "Unselected all!"
foreach (ListViewItem item in collection)
getSideInformation(item.Text);
}
It shouldn't matter whether you use ItemSelectionChanged or SelectedIndexChanged. Both will work fine in this case.
Big thanks goes to Grammarian for his answer to essentially the same question here: https://stackoverflow.com/a/26393234/2532220
you can use the below code inside the event block to check whether the
SelectedIndexChange event is firing directly because of the control or due to
some postback event from some other usercontrols/Pages
string id= Request.Form["__EVENTTARGET"];
if(!string.IsNullorEmpty(id))
{
//your code here
}
You can do something like this:
private bool isInitialized = false;
private void listView1_SelectedIndexChanged(object sender, EventArgs e) {
if (isInitialized) {
ListView.SelectedListViewItemCollection collection = this.listView1.SelectedItems;
if (collection.Count == 0) {
this.label2.Text = "Unselected all!";
}
foreach (ListViewItem item in collection) {
getSideInformation(item.Text);
}
}
isInitialized = true;
}
That will insure that first firing is ignored.
I have a list box with some items. Is there anyway I can attach a double click event to each item?
Item 1
Item 2
Item 3
If i was to double click Item 2, a Messagebox saying "Item 2" would pop up
How would i do this?
void listBox1_MouseDoubleClick(object sender, MouseEventArgs e)
{
int index = this.listBox1.IndexFromPoint(e.Location);
if (index != System.Windows.Forms.ListBox.NoMatches)
{
MessageBox.Show(index.ToString());
}
}
This should work...check
WinForms
Add an event handler for the Control.DoubleClick event for your ListBox, and in that event handler open up a MessageBox displaying the selected item.
E.g.:
private void ListBox1_DoubleClick(object sender, EventArgs e)
{
if (ListBox1.SelectedItem != null)
{
MessageBox.Show(ListBox1.SelectedItem.ToString());
}
}
Where ListBox1 is the name of your ListBox.
Note that you would assign the event handler like this:
ListBox1.DoubleClick += new EventHandler(ListBox1_DoubleClick);
WPF
Pretty much the same as above, but you'd use the MouseDoubleClick event instead:
ListBox1.MouseDoubleClick += new RoutedEventHandler(ListBox1_MouseDoubleClick);
And the event handler:
private void ListBox1_MouseDoubleClick(object sender, RoutedEventArgs e)
{
if (ListBox1.SelectedItem != null)
{
MessageBox.Show(ListBox1.SelectedItem.ToString());
}
}
Edit: Sisya's answer checks to see if the double-click occurred over an item, which would need to be incorporated into this code to fix the issue mentioned in the comments (MessageBox shown if ListBox is double-clicked while an item is selected, but not clicked over an item).
Hope this helps!
I know this question is quite old, but I was looking for a solution to this problem too. The accepted solution is for WinForms not WPF which I think many who come here are looking for.
For anyone looking for a WPF solution, here is a great approach (via Oskar's answer here):
private void myListBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
DependencyObject obj = (DependencyObject)e.OriginalSource;
while (obj != null && obj != myListBox)
{
if (obj.GetType() == typeof(ListBoxItem))
{
// Do something
break;
}
obj = VisualTreeHelper.GetParent(obj);
}
}
Basically, you walk up the VisualTree until you've either found a parent item that is a ListBoxItem, or you ascend up to the actual ListBox (and therefore did not click a ListBoxItem).
For Winforms
private void listBox1_DoubleClick(object sender, MouseEventArgs e)
{
int index = this.listBox1.IndexFromPoint(e.Location);
if (index != System.Windows.Forms.ListBox.NoMatches)
{
MessageBox.Show(listBox1.SelectedItem.ToString());
}
}
and
public Form()
{
InitializeComponent();
listBox1.MouseDoubleClick += new MouseEventHandler(listBox1_DoubleClick);
}
that should also, prevent for the event firing if you select an item then click on a blank area.
It depends whether you ListBox object of the System.Windows.Forms.ListBox class, which does have the ListBox.IndexFromPoint() method. But if the ListBox object is from the System.Windows.Control.Listbox class, the answer from #dark-knight (marked as correct answer) does not work.
Im running Win 10 (1903) and current versions of the .NET framework (4.8). This issue should not be version dependant though, only whether your Application is using WPF or Windows Form for the UI.
See also: WPF vs Windows Form
This is very old post but if anyone ran into similar problem and need quick answer:
To capture if a ListBox item is clicked use MouseDown event.
To capture if an item is clicked rather than empty space in list box check if listBox1.IndexFromPoint(new Point(e.X,e.Y))>=0
To capture doubleclick event check if e.Clicks == 2
The post is old but there is a simple solution for those who need it
private void listBox1_DoubleClick(object sender, EventArgs e)
{
if (listBox1.SelectedIndex > -1)
{
MessageBox.Show(listBox1.Items[listBox1.SelectedIndex].ToString());
}
}
I have a windows form with a listview control. I set the MultiSelect property to true and I added a selected_index changed event.
I get the event fired when I click the same index as the current selected index.
My expectation is that I will not get the event fired. The strange thing is that the event fired 1 second after I click the index.
I appreciate for any reply to explain why this is happening.
Edited:
Sample Code:
private void Form1_Load(object sender, EventArgs e)
{
listView1.View = View.Details;
listView1.MultiSelect = true;
listView1.FullRowSelect = true;
listView1.Columns.Add("Number");
listView1.Items.Add("1");
listView1.Items.Add("2");
listView1.Items.Add("3");
listView1.Items.Add("4");
}
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count > 0)
{
MessageBox.Show("Selected Index Changed event fired: ");
}
}
Follow these steps to see the problem:
Try to select one item, for instance: select number 3
expected result: listview1_SelectedIndexChanged is fired
Result: It is fired.
Try to click the number 3 again.
expected result: listview1_SelectedIndexChanged is NOT fired
Result: It is fired with one second delay.
From the MSDN documention on ListView.SelectedIndexChangedEvent:
In a multiple selection ListView control, this event occurs whenever an item is removed or added to the list of selected items. To determine which items are selected in the ListView control, use the SelectedItems property to access the ListView.SelectedListViewItemCollection.
As for why the event waited so long to fire: I can only imagine the processor was tied up doing something else. Do you have more details regarding what you're seeing, exactly (sample code would help)?
I have a C# ComboBox using WPF. I have code that executes when the ComboBox's GotFocus is activated. The issue is that the GotFocus event is executed every time a selection is made from the ComboBox. For example, the GotFocus is executed when you first click on the ComboBox and then when you make a selection even though you have not click on any other control.
Is it possible to prevent this event from firing if a selection is being made in the list or is there a flag or something else in the event handler that can be used to determine if the GotFocus event handler was fired as a result of the user selecting an item in the list?
You can solve this problem with next verification:
private void myComboBox_GotFocus(object sender, RoutedEventArgs e)
{
if (e.OriginalSource.GetType() == typeof(ComboBoxItem))
return;
//Your code here
}
This code will filter all focus events from items (because they use bubble routing event). But there is another problem - specific behaviour of WPF ComboBox focus: when you open drop-down list with items your ComboBox losing focus and items get. When you select some item - item losing focus and ComboBox get back. Drop-down list is like another control. You can see this by simple code:
private void myComboBox_GotFocus(object sender, RoutedEventArgs e)
{
if (e.OriginalSource.GetType() != typeof(ComboBoxItem))
{
Trace.WriteLine("Got " + DateTime.Now);
}
}
private void myComboBox_LostFocus(object sender, RoutedEventArgs e)
{
if (e.OriginalSource.GetType() != typeof(ComboBoxItem))
{
Trace.WriteLine("Lost " + DateTime.Now);
}
}
So you will get anyway atleast two focus events: when you select ComboBox and when you selecting something in it (focus will return to ComboBox).
To filter returned focus after selecting item, you can try to use DropDownOpened/DropDownClosed events with some field-flag.
So the final code with only 1 event of getting focus:
private bool returnedFocus = false;
private void myComboBox_GotFocus(object sender, RoutedEventArgs e)
{
if (e.OriginalSource.GetType() != typeof(ComboBoxItem) && !returnedFocus)
{
//Your code.
}
}
private void myComboBox_LostFocus(object sender, RoutedEventArgs e)
{
if (e.OriginalSource.GetType() != typeof(ComboBoxItem))
{
ComboBox cb = (ComboBox)sender;
returnedFocus = cb.IsDropDownOpen;
}
}
Choose from this examples what you actually need more for your application.
I'm not too hot on WPF; but if you're trying to detect changes to the list (click on new value etc) you can use SelectedIndexChanged events..
On the other hand, if you really do want to know simply when the control is focussed, can you filter it by saying something like;
if (combo1.Focused && combo1.SelectedIndex == -1)
{
...
}
.. ? It really depends on what youre trying to detect, exactly.
Another solution is used is to determine whether the new focused element is an existing item in the combobox. If true then the LostFocus event should not be performed, because the combobox still has focus. Otherwise an element outside the combobox received focus.
In the code snipplet below I added the functionality in a custom combobox class
public class MyComboBox : System.Windows.Controls.Combobox
{
protected override void OnLostFocus(RoutedEventArgs e)
{
//Get the new focused element and in case this is not an existing item of the current combobox then perform a lost focus command.
//Otherwise the drop down items have been opened and is still focused on the current combobox
var focusedElement = FocusManager.GetFocusedElement(FocusManager.GetFocusScope(this));
if (!(focusedElement is ComboBoxItem && ItemsControl.ItemsControlFromItemContainer(focusedElement as ComboBoxItem) == this))
{
base.OnLostFocus(e);
/* Your code here... */
}
}
}
I've got two ListBox'es that are databound to the same BindingList.
The issue is that when changing the selected item from the GUI it's changing the position in the BindingList and then the BindingList signals the other ListBox to change its selected item.
So I've got the two ListBoxes Selected Item also synchronized which is not good for me.
I'd like to maintain the list of items in sync. without the cursor position.
How do I disable that cursor so it's not maintained?
sample code (just add two ListBoxes to the Form at design time and register the SelectedIndexChanged events and register the button click event with a button):
public partial class Form1 : Form
{
BindingList<string> list = new BindingList<string>();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
list.Add("bla1");
list.Add("bla2");
list.Add("bla3");
this.listBox1.DataSource = list;
this.listBox2.DataSource = list;
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (listBox1.SelectedIndex != -1)
System.Diagnostics.Trace.WriteLine("ListBox1: " + listBox1.SelectedItem.ToString());
}
private void listBox2_SelectedIndexChanged(object sender, EventArgs e)
{
if (listBox2.SelectedIndex != -1)
System.Diagnostics.Trace.WriteLine("ListBox2: " + listBox2.SelectedItem.ToString());
}
// Register this event to a button
private void button1_Click(object sender, EventArgs e)
{
list.Add("Test");
}
}
Thanks,
--Ran.
Add this line to Form_Load:
this.listBox1.BindingContext = new BindingContext();
Declaring listBox1 and listBox2 to be of the following type seems to result in the desired behaviour.
class MyListBox: ListBox {
protected override void OnSelectedIndexChanged (EventArgs a) {
if (DataManager != null) {
DataManager.SuspendBinding();
}
}
}
Regards,
tamberg
My solution for this issue is to use a normal List instead of the BindingList and just call (before the change) on the Form object:
this.BindingContext[Your List].SuspendBinding();
and after the change to the List
this.BindingContext[Your List].ResumeBinding();
This updates all the bounded controls.
Notice it's also noted in the MSDN link here:
"If you are bound to a data source that does not implement the IBindingList interface, such as an ArrayList, the bound control's data will not be updated when the data source is updated. For example, if you have a combo box bound to an ArrayList and data is added to the ArrayList, these new items will not appear in the combo box. However, you can force the combo box to be updated by calling the SuspendBinding and ResumeBinding methods on the instance of the BindingContext class to which the control is bound."