Catching Unselecting All in ListView -- SelectedIndexChanged Firing Twice - c#

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.

Related

Selected index changed fail into ListBox

I created a windows forms like this
As you can see in selected changed event I disable button move to, it works correctly, problem starts when I try to
return an item it to main list, move to button keeps disable instead enable it again when I select item of first list. Someone knows
what occurs there?
Events:
private void lstTechUnnotified_SelectedIndexChanged(object sender, EventArgs e)
{
btnReturnTo.Enabled = false;
btnMoveTo.Enabled = true;
}
private void lstTechToNotified_SelectedIndexChanged(object sender, EventArgs e)
{
btnReturnTo.Enabled = true;
btnMoveTo.Enabled = false;
}
You need to make sure that there actually is an item being selected since ListBox.SelectedIndexChanged event gets fired even when there're no items selected - making the new SelectedIndex equal to -1. Also, from the way you asking, I expect you want to enable btnMoveTo when there's a selected item in lstTechUnnotified and otherwise, disable it - and the same for btnReturnTo and lstTechToNotified; if that's it, then the easy way is:
private void lstTechUnnotified_SelectedIndexChanged(object sender, EventArgs e)
{
btnMoveTo.Enabled = (lstTechUnnotified.SelectedIndex > -1);
}
private void lstTechToNotified_SelectedIndexChanged(object sender, EventArgs e)
{
btnReturnTo.Enabled = (lstTechToNotified.SelectedIndex > -1);
}
Though I'm not sure about your button names..

Is there a way to do multiselect in ObjectListView without the Ctrl key pressed?

I set the FullRowSelect and MultiSelect property to true in the ObjectListView component, but I still have to select multiple rows by pressing the Ctrl key. So, Is there a way to do multiselect without the Ctrl or shift key pressed?
I think I have a working solution. The model objects in this example are of type "Item". For some explanations see code comments.
// We require a list to remember which items should stay selected
private List<Item> _MultiSelectList;
public Form1() {
// <other stuff>
_MultiSelectList = new List<Item>();
}
// use this event to check which item has been clicked
private void objectListView1_MouseClick(object sender, MouseEventArgs e) {
objectListView1.BeginUpdate();
// any item clicked?
if (objectListView1.MouseMoveHitTest.Item != null) {
var item = objectListView1.MouseMoveHitTest.Item.RowObject as Item;
// model object of expected type available?
if (item != null) {
// add or remove item from list to effectively toggle selection
if (_MultiSelectList.Contains(item)) {
_MultiSelectList.Remove(item);
} else {
_MultiSelectList.Add(item);
}
}
}
// select all desired items
objectListView1.SelectObjects(_MultiSelectList);
objectListView1.EndUpdate();
}
// optional: to prevent flickering from the native item selection change, we freeze the OLV contents during the mouse click
private void objectListView1_MouseDown(object sender, MouseEventArgs e) {
objectListView1.Freeze();
}
private void objectListView1_MouseUp(object sender, MouseEventArgs e) {
objectListView1.Unfreeze();
}

MultiSelect ListBox Select And DeSelect Event

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 :)

C# Listbox Item Double Click Event

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());
}
}

C# ComboBox GotFocus

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... */
}
}
}

Categories