Best way to change ListBox selection for radio button selection

I have a ListBox control that I want to change to a radio button selection. those. click once on the item that will select it, click again to deselect it. Additionally, clicking on another item in the list should perform the default action to deselect the previous item and select a new one.

What's the best way to achieve this?

+1


source to share


5 answers


What you want is a RadioButtonList. You can create it by creating an ItemDataTemplate and placing a RadioButton in it. Then you can change the RadioButton template to look like a button.



+2


source


I would keep a standard ListBox in such a way that you still follow the default behavior, and then to deselect an item, you could just handle it on a mouse down event? for example use something like this:

Point newPoint = e.GetPosition(backgroundImage);

HitTestResult result = VisualTreeHelper.HitTest(this, newPoint);

if (result.VisualHit is ListBoxItem)

      



I'm not sure if this is the best way, the only way I would like to do it is to get my own ListBox from a standard Windows control and add a dependency property to allow me to handle cancellation in style. If you want to take this approach, I shouldn't remove the default behavior that you want to keep, I used this approach to create a ListBox that displays an image next to the text.

If you need any pointers on where to start, then just give me a shout.

0


source


I managed to achieve this by creating a few custom ToggleListBox and ToggleListBoxItem classes. There are some handy overrides (the most important one in the ToggleListBox is the one that creates your ListBoxItem).

From there, it was easy to deal with one click on the same item or pressing the spacebar / enter key. 40 lines of code for both classes and works great.

0


source


Just in case anyone is interested, I found another solution for this which worked well for me. I set ListBox.SelectionMode

to Multiple

and handled the MouseDown event this way:

EventManager.RegisterClassHandler(typeof(ListBoxItem),
    ListBoxItem.MouseLeftButtonDownEvent,
    new RoutedEventHandler(this.HandleListBox_MouseDown));

...

void HandleListBox_MouseDown(object sender, RoutedEventArgs e)
{
    var listBoxItem = (ListBoxItem)sender;
    if (ShouldDeselectOtherListItems(listBoxItem))
    {
        listBox.SelectedIndex = -1;
    }
}

bool ShouldDeselectOtherListItems(ListBoxItem listBoxItem)
{
    return !listBoxItem.IsSelected
        && listBox.SelectedItems.Count > 0;
}

      

Where listBox is the parent of the ListBox control. This ensures that all list items are deselected before the system's MouseDown event handlers are handled, allowing you to toggle the selection state of the list item.

0


source


I decided to find a "built-in" way to do this. When I saw they weren't there and noticed answers here that I didn't really like, I decided to post what I think is the best way to do it.

This answer is most similar to Bijington's answer I just added a PreviewMouseDown handler to the ListBox

<ListBox ... PreviewMouseLeftButtonDown="ListBox_OnPreviewMouseLeftButtonDown"... />

      

Then in the code

private void ListBox_OnPreviewMouseLeftButtonDown (object sender, MouseButtonEventArgs e)
{
    // I have a special extension for GetParent, numerous examples on the internet of how you would do that
    var lbi = ((DependencyObject) e.OriginalSource).GetParent<ListBoxItem>();
    if (lbi != null && lbi.IsSelected)
    {
        lbi.IsSelected = false;
        e.Handled = true;
    }
}

      

Then I thought it would be nice to turn this into an attached property, so here is some psedo code to explain how this can be done ...

public static class ListBoxEx
{
    private static DependencyProperty ToggleSelectionProperty = DependencyProperty.RegisterAttached(..., HandleToggleSelectionChanged);
    private static bool GetToggleSelection (DependencyObject obj) => (bool)obj.GetValue(ToggleSelectionProperty);
    private static void SetToggleSelection (DependencyObject obj, bool shouldToggle) => obj.SetValue(ToggleSelectionProperty, shouldToggle);

    private static void HandleToggleSelectionChanged (DependencyObject obj)
    {
        if (obj is ListBox listBoxObj)
        {
           bool shouldToggle = GetToggleSelection(obj);
           if (shouldToggle)
           {
               listBoxObj.PreviewMouseLeftButtonDown += ToggleListBox_OnPreviewMouseLeftButtonDown ;
           }
           else
           {
               listBoxObj.PreviewMouseLeftButtonDown -= ToggleListBox_OnPreviewMouseLeftButtonDown ;
           }
        }
    }

    private static void ToggleListBox_OnPreviewMouseLeftButtonDown (object sender, MouseButtonEventArgs e)
    {
        // I have a special extension for GetParent, numerous examples on the internet of how you would do that
        var lbi = ((DependencyObject) e.OriginalSource).GetParent<ListBoxItem>();
        if (lbi != null && lbi.IsSelected)
        {
            lbi.IsSelected = false;
            e.Handled = true;
        }
    }
}

      

Then in code:

<ListBox ... yourNamespace:ListBoxEx.ToggleSelection="True" />

      

Relevant information:

0


source







All Articles