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

21,795

Solution 1

try that:

you use a ToggleButton as the "Expander" of the detailed content. The "IsChecked" Property of the toggle Button you can bind to the IsSelected Property of the item

here the code:

<ListBox SelectionMode="Single">
   <ListBox.ItemsSource>
      <x:Array Type="{x:Type sys:String}">
         <sys:String>test1</sys:String>
         <sys:String>test2</sys:String>
         <sys:String>test3</sys:String>
         <sys:String>test4</sys:String>
         <sys:String>test5</sys:String>
         <sys:String>test6</sys:String>
      </x:Array>
   </ListBox.ItemsSource>
   <ListBox.ItemTemplate>
      <DataTemplate>
         <StackPanel Orientation="Horizontal">
            <ToggleButton IsChecked="{Binding 
                          RelativeSource={RelativeSource FindAncestor, 
                          AncestorType={x:Type ListBoxItem}},
                          Path=IsSelected}"
            >btn</ToggleButton>
         </StackPanel>
      </DataTemplate>
   </ListBox.ItemTemplate>
</ListBox>

how it works: In the Listbox can only one item be selected. As we select an item the Toggler gets expanded cause his IsChecked is bound to ListBoxItem.IsSelected (ListBoxItem is a Control which gets wrapped around the Content of each Item) of his parent ListBoxItem. As the selectionMode is single as soon as another item gets selected the following happens:

  • Deselect the actually selected item
  • Through the binding the Toggler gets unchecked too
  • Select the new item
  • the New items toggler gets checked through its binding

and if just the actually selected item's toggler gets unchecked the item deselects itself through the binding...

Solution 2

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);
                }
            }
        }
    }
}
Share:
21,795

Related videos on Youtube

Tor Thorbergsen
Author by

Tor Thorbergsen

Updated on February 28, 2020

Comments

  • Tor Thorbergsen
    Tor Thorbergsen about 4 years

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

  • Tor Thorbergsen
    Tor Thorbergsen about 13 years
    I do not have a problem with the expansion-on-select, the problem is to make the listbox select only one item at a time, and to un-select on second click.
  • fixagon
    fixagon about 13 years
    but it does exactly that. on togglebuttonclick it expands and selects the item. on second click it collapses and deselects the item. and there is max 1 item selected. the trick is the 2-way binding on the IsSelected Property of the ListBoxItem. just try it
  • Tor Thorbergsen
    Tor Thorbergsen about 13 years
    I stand corrected, you are right, and the solution is brilliant. Thank you! I must say that I'm a bit uncertain to how this actually works? 1. The togglebutton is clicked -> the tb is checked -> the listviewitem is selected -> any other listviewitem is unselected 2. the tb is clicked again -> the tb is unchecked -> the listviewitem is unselected... Is this correctly put?
  • fixagon
    fixagon about 13 years
    i edited the explanation inside the answer. yes its exactly that
  • Daniel
    Daniel about 10 years
    Do you know why am I unable to deselect the ListBoxItem throught the same ToggleButton. Only selection works.
  • Romain Hautefeuille
    Romain Hautefeuille over 9 years
    I like this solution better than the accepted one, as it does not involve tricks with UI elements.
  • Romain Hautefeuille
    Romain Hautefeuille over 9 years
    Seems nice but how do you get rid of the togglebutton, show a custom content for the ListBoxItem (basically two textblocks) and still be able to acheive the selection toggling result?
  • fixagon
    fixagon over 9 years
    @RomainHautefeuille : just place the custom content within the toggle button. (if you have multiple items within a stackpanel or similar)
  • Alex Riabov
    Alex Riabov over 5 years
    While this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value.