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

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


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


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...


My solution is set ListBox SelectionMode to Multiple, add method forbidSelectionButOne on Click event and after that allow only one selected item as follows:

Private Sub forbidSelectionButOne(sender As Object, e As MouseButtonEventArgs)    Dim lv As ListView = TryCast(sender, ListView)    If lv IsNot Nothing Then        If lv.SelectedIndex <> getCausesListViewItemIndex(sender, e) Then            lv.SelectedIndex = getCausesListViewItemIndex(sender, e)            e.Handled = True        End If        lv.Focus()    End IfEnd Sub

And helping function to find ListViewItem that was clicked by mouse:

Private Function getCausesListViewItemIndex(ByVal sender As Object, e As RoutedEventArgs) As Integer    Dim dep As DependencyObject = TryCast(e.OriginalSource, DependencyObject)    Do While dep IsNot Nothing AndAlso Not TypeOf (dep) Is ListViewItem        dep = VisualTreeHelper.GetParent(dep)    Loop    If dep Is Nothing Then        Return -1    Else        Dim lv As ListView = TryCast(sender, ListView)        If lv IsNot Nothing Then            Dim i As Integer = lv.ItemContainerGenerator.IndexFromContainer(dep)            Return i        Else            Return -1        End If    End IfEnd Function