Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie

c# Listview ItemSelectionChanged, please help

Options
  • 30-01-2013 6:12pm
    #1
    Registered Users Posts: 3,411 ✭✭✭


    Dearly beloved,

    Bit embarrassed by this, I feel I should be able to solve it but basically, have a look at the code below. The Listview ItemSelectionChanged event fires twice and thus I get the UserClosedSession dialog twice. Is there a way to suppress the second dialog ?

    Basically, I'm trying to do some validation when user clicks on an item in a Listview. When changing the selected item, they get asked a question, if yes then go ahead and select the new item, if no then "undo" the selection. The code below is a simple sample only of the real world problem. Ignore the content of UserClosedSession, it is just used here to mimic what needs to happen.

    I have tried all sorts. Tried the mouse click / mouse down events. But these are no good if the user changes selections with the keyboard. I have also tried un-wiring and then re-wiring the ItemSelectionChangedevent from withing itself (see commented out code) - doesn't work.

    Can anyone help? Much appreciated if you can
            private void lv_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
            {
                if (e.IsSelected)
                {
                    Debug.WriteLine("Index: " + lv.SelectedIndices[0].ToString());
                    if (lv.Tag != null)
                    {
                        if ((int)lv.Tag != lv.SelectedIndices[0])
                        {
    
                            if (!UserClosedSession())
                            {
                                //lv.ItemSelectionChanged -= new ListViewItemSelectionChangedEventHandler(lv_ItemSelectionChanged);
                                //lv.ItemSelectionChanged -= lv_ItemSelectionChanged;
                                lv.Items[(int)lv.Tag].Selected = true;
                                //lv.ItemSelectionChanged +=new ListViewItemSelectionChangedEventHandler(lv_ItemSelectionChanged);
                                return;
                            }
                        }
                    }
                    else
                        lv.Tag = lv.SelectedIndices[0];
                }
            }
    
    
            private bool UserClosedSession()
            {
                return
                    (MessageBox.Show("Close Session?", "", MessageBoxButtons.YesNo) == DialogResult.Yes);
            }
    


Comments

  • Registered Users Posts: 11,979 ✭✭✭✭Giblet


    Selecting a new item is the issue. You should probably unbind the event differently, as "-= new ListViewItemSelectionChangedEventHandler(lv_ItemSelectionChanged)" will probably do nothing. You should keep a reference to the event handler you have bound originally.

    var eventHandler = new ListViewItemSelectionChangedEventHandler(lv_ItemSelectionChanged);

    lv.ItemSelectionChanged += eventHandler


    lv.ItemSelectionChanged -= eventHandler


  • Registered Users Posts: 3,411 ✭✭✭dnme


    Hi Gilbert,

    I've tried that as per code below. It still fires twice and won't work. Am I doing it right?
    public partial class Form1 : Form
        {
    
            ListViewItemSelectionChangedEventHandler eventHandler;
    
            public Form1()
            {
                InitializeComponent();
                eventHandler = new ListViewItemSelectionChangedEventHandler(lv_ItemSelectionChanged);
                lv.ItemSelectionChanged += eventHandler;
            }
    
            void lv_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
            {
                if (e.IsSelected)
                {
                    if (lv.Tag != null)
                    {
                        if ((int)lv.Tag != lv.SelectedIndices[0])
                        {
    
                            if (!UserClosedSession())
                            {
                                lv.ItemSelectionChanged -= eventHandler;
                                lv.Items[(int)lv.Tag].Selected = true;                            
                                lv.ItemSelectionChanged += eventHandler;
                                return;
                            }
                        }
                    }
                    else
                        lv.Tag = lv.SelectedIndices[0];
                }
            }
    
    
            private bool UserClosedSession()
            {
                return
                    (MessageBox.Show("Close Session?", "", MessageBoxButtons.YesNo) == DialogResult.Yes);
            }
    
    
            private void buttonClose_Click(object sender, EventArgs e)
            {
                Close();
            }
    
        }
    


  • Registered Users Posts: 1,686 ✭✭✭RealistSpy


    I hope this can help you out:

    Mouse Down Event on List View - Just noticed you have done that
    if(e.Button == MouseButton.Left)
    {
    ListViewItem item = ListView.GetItemAt(e.x, e.y);
    if(item == null) return;
    int itemIndex = item.Index;
    
    
    

    Using your code why not try use a boolean semaphore?
    private bool locked;
    private void lv_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
            {
             if(locked) return;
              
               locked == true;
                if (e.IsSelected)
                {
                    Debug.WriteLine("Index: " + lv.SelectedIndices[0].ToString());
                    if (lv.Tag != null)
                    {
                        if ((int)lv.Tag != lv.SelectedIndices[0])
                        {
    
                            if (!UserClosedSession())
                            {
                                //lv.ItemSelectionChanged -= new ListViewItemSelectionChangedEventHandler(lv_ItemSelectionChanged);
                                //lv.ItemSelectionChanged -= lv_ItemSelectionChanged;
                                lv.Items[(int)lv.Tag].Selected = true;
                                //lv.ItemSelectionChanged +=new ListViewItemSelectionChangedEventHandler(lv_ItemSelectionChanged);
                                return;
                            }
                        }
                    }
                    else
                        lv.Tag = lv.SelectedIndices[0];
                }
            }
          
    
    
    


  • Registered Users Posts: 3,411 ✭✭✭dnme


    Hi RealistSpy

    I cannot get that to work either. Ive been messing around with boolean switches a lot and can't seem to nail it. There has to be a way around this?


  • Registered Users Posts: 11,979 ✭✭✭✭Giblet


    It fires twice because one item is becoming selected, and another is becoming deselected. To differentiate, use the IsSelected flag (which you do). You can't prevent this as both events are queued before you get to unbind them. It's supposed to fire twice.


  • Advertisement
  • Registered Users Posts: 3,411 ✭✭✭dnme


    Giblet wrote: »
    It fires twice because one item is becoming selected, and another is becoming deselected. To differentiate, use the IsSelected flag (which you do). You can't prevent this as both events are queued before you get to unbind them. It's supposed to fire twice.

    I know it fires twice, I'm capturing the fired event only when items are selected using the IsSelected flag. The problem is that within the method I'm calling
    lv.Items[(int)lv.Tag].Selected = true;
    
    (effectively calling the ItemSelectionChanged again from within itself) which is why the UserClosedSession() is popping up twice.

    I cannot seem to get a handle on this. How do I stop that UserClosedSession() from popping up twice?


  • Registered Users Posts: 3,411 ✭✭✭dnme


    Here's a project, with the above code. Leave the Session Open checkbox checked, select an item in the listview, then select another. If you answer No, you'll see the issue. In this project I have changed from the Listview_ItemSelectionChanged event to the ListView_lv_SelectedIndexChanged event. They both behave exactly the same way. Can anyone help?


  • Registered Users Posts: 1,686 ✭✭✭RealistSpy


    Do you have to use a list view? Would a combobox not be better?


  • Registered Users Posts: 7,501 ✭✭✭BrokenArrows


    You are activating a second select inside lv_SelectedIndexChanged
    That change is causing it to reeneter lv_SelectedIndexChanged a second time.
    private void lv_SelectedIndexChanged(object sender, EventArgs e)
            {            
                if (lv.SelectedItems.Count == 1)
                {
                    if (lv.Tag != null)
                    {
                        if ((int)lv.Tag != lv.SelectedIndices[0])
                        {
    
                            if (!UserClosedSession())
                            {
                                [COLOR="Red"][U][B]lv.Items[(int)lv.Tag].Selected = true;[/U][/B][/COLOR]
                                return;
                            }
                        }
                    }
                    else
                        lv.Tag = lv.SelectedIndices[0];
                }
    
            }
    


  • Registered Users Posts: 3,411 ✭✭✭dnme


    RealistSpy wrote: »
    Do you have to use a list view? Would a combobox not be better?

    Not really, its not my project, and the existing code is huge and convoluted. This issue is a bug and I have abstracted it down to a simple little project here for simplification purposes.


  • Advertisement
  • Registered Users Posts: 1,686 ✭✭✭RealistSpy


    dnme wrote: »
    Not really, its not my project, and the existing code is huge and convoluted. This issue is a bug and I have abstracted it down to a simple little project here for simplification purposes.

    I was able to remove the double message box from popping up but other problems occurred like the first item getting selected even though you select something else.


  • Registered Users Posts: 3,411 ✭✭✭dnme


    To offer an answer to my own question, this works and seems to work well. If anyone can improve on it let me know.
            private bool b;
            void lv_SelectedIndexChanged(object sender, EventArgs e)
            {
                if (lv.SelectedIndices.Count == 1)
                {
                    if (lv.Tag != null)
                    {
                        if ((int)lv.Tag != lv.SelectedIndices[0])
                        {
                            if (!b)
                            {
                                if (!UserClosedSession())
                                {
                                    lv.Items[(int)lv.Tag].Selected = true;
                                    b = true;
                                }
                            }
                            else
                            {
                                lv.Items[(int)lv.Tag].Selected = true;
                                b = false;
                            }
                        }
                    }
                }
                if (lv.SelectedIndices.Count > 0) lv.Tag = lv.SelectedIndices[0];
            }
    
    


Advertisement