ListBox with single select and also unselect on click...?

Tor Thorbergsen picture Tor Thorbergsen · Feb 28, 2011 · Viewed 20.3k times · Source

I need a listbox that selects on first click and un-selects on second click, so that only zero or one item is selected at any time.

The select/unselect is implemented in the listbox (with SelectionMode="Single") when you hold down crtl, but unfortunately, none of my users can be expected to know that.

With SelectionMode="Multiple" we have the exact functionality I want, except that you can select more than one item...

More background: I want the user to first choose which installation to log into, then to give credentials (and some other choices)

To achieve this I have used a listbox with expanding content. To aid the expansion I have on the left side of the listboxitem made a triangle that points right when unexpanded that turns to point down when you have selected the listbox item.

So, first the user see the list over the installations, and then, when he has chosen the item he wants by selecting it, the listboxitem expands to the rest of the info he need to enter. It's quite nice, and works well, but testing reports that they want a second click to the triangle to unselect (and thus collapse the expanded section). And I must admit that I have clicked the ¤%& arrow too, expecting the action to result in a collapse... :-(

Anyone has an idea how this can be achieved (preferably without code behind)?

Answer

Fredrik Hedblad picture Fredrik Hedblad · Feb 28, 2011

The common way to do this is to set SelectionMode mode to Multiple and then unselect all items but the newly selected one in the SelectionChanged event.

See the follow links

Here is an Attached Behavior that does this which can be used like this

<ListBox local:ListBoxSelectionBehavior.ClickSelection="True"
         ...>

ListBoxSelectionBehavior

public static class ListBoxSelectionBehavior 
{
    public static readonly DependencyProperty ClickSelectionProperty = 
        DependencyProperty.RegisterAttached("ClickSelection", 
                                            typeof(bool),
                                            typeof(ListBoxSelectionBehavior),
                                            new UIPropertyMetadata(false, OnClickSelectionChanged));
    public static bool GetClickSelection(DependencyObject obj) 
    {
        return (bool)obj.GetValue(ClickSelectionProperty); 
    }
    public static void SetClickSelection(DependencyObject obj, bool value) 
    {
        obj.SetValue(ClickSelectionProperty, value); 
    }
    private static void OnClickSelectionChanged(DependencyObject dpo, 
                                                             DependencyPropertyChangedEventArgs e) 
    {
        ListBox listBox = dpo as ListBox;
        if (listBox != null) 
        { 
            if ((bool)e.NewValue == true) 
            {
                listBox.SelectionMode = SelectionMode.Multiple;
                listBox.SelectionChanged += OnSelectionChanged;
            } 
            else 
            {
                listBox.SelectionChanged -= OnSelectionChanged;
            } 
        } 
    }
    static void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (e.AddedItems.Count > 0)
        {
            ListBox listBox = sender as ListBox;
            var valid = e.AddedItems[0];
            foreach (var item in new ArrayList(listBox.SelectedItems))
            {
                if (item != valid)
                {
                    listBox.SelectedItems.Remove(item);
                }
            }
        }
    }
}