5

I have a wpf listbox with a custom item template which contains a rectangle. The each item in the listbox can be selected (only one at a time). I want to add a behavior in which when a user clicks on a place which isn't the item (for instance, a blank spot on the listbox, which is not an item), the selected item will become deselected.

Any ideas? Thanks.

For example with a simple listbox: item 1 item 2

The behavior that I'm looking for is when the user clicks on pixel 500 (which is a part of the listbox but not on an item), the currently selected item will be deselected.

Joe DF
  • 5,438
  • 6
  • 41
  • 63
user2853648
  • 73
  • 1
  • 4

4 Answers4

9

The simple solution is to data bind a property to the ListBox.SelectedItem property and set it to null whenever you want to clear the selection:

<ListBox ItemsSource="{Binding YourItems}" SelectedItem="{Binding SelectedItem}" 
    SelectionMode="Single" />

Then in code, you can just do this to clear the selection:

SelectedItem = null;

And when would you do that? You can attach a handler to the PreviewMouseLeftButtonDown event of the Window, or any other control in your UI. In the handler method, you could do a hit test to see what the item the user clicked on was:

HitTestResult hitTestResult = 
    VisualTreeHelper.HitTest(controlClickedOn, e.GetPosition(controlClickedOn));
Control controlUnderMouse = hitTestResult.VisualHit.GetParentOfType<Control>();

See the VisualTreeHelper.HitTest Method (Visual, Point) for more help with this part.

Then maybe something like this:

if (controlUnderMouse.GetType() != typeof(ListBoxItem)) SelectedItem = null;

Of course, there are many ways to do this, and you'll have to fill in the few blank spots that I left, but you should get the idea.


EDIT >>>

The generic GetParentOfType method is a custom Extension Method that is defined in a separate class named DependencyObjectExtensions:

public static class DependencyObjectExtensions
{
    public static T GetParentOfType<T>(this DependencyObject element) 
        where T : DependencyObject
    {
        Type type = typeof(T);
        if (element == null) return null;
        DependencyObject parent = VisualTreeHelper.GetParent(element);
        if (parent == null && ((FrameworkElement)element).Parent is DependencyObject) 
            parent = ((FrameworkElement)element).Parent;
        if (parent == null) return null;
        else if (parent.GetType() == type || parent.GetType().IsSubclassOf(type)) 
            return parent as T;
        return GetParentOfType<T>(parent);
    }

    ...
}
Sheridan
  • 68,826
  • 24
  • 143
  • 183
0

For The each item in the listbox can be selected (only one at a time).

You can come up with one of followings

1- Disable the item after it is selected.

2- Maintain a list at backend to mark each index selectable or unselectable.

Ahsan
  • 648
  • 1
  • 10
  • 27
0

To assure that only one item is selected put this in the listbox:

SelectionMode="Single"

then for the unselect when clicking somewhere, you can try to check this events

PreviewMouseLeftButtonUp
LostFocus()

Regards,

sexta13
  • 1,558
  • 1
  • 11
  • 19
0

I was searching for a solution to this problem, but to prevent the last item in the listbox from becoming selected when clicking on the blank space. my problem is slightly different but has the same solution that I have come up with which works for me.

Although I am using powershell and not c#, I am still utilizing the windows forms listbox control so I think the idea will be applicable.

Also, I couldn't find any discussions of this problem specifically dealing with powershell when I was searching for a solution, so I wound up here.

so I created a variable, maxY, and multiplied the number of list items by the itemheight.

next, at the beginning of the mouse_up event, I just check if the Y location from the mouse click is less than the maxY variable. if true, select the item and run your code, if not, do nothing.

I can only provide a code sample in powershell, but I think the idea is portrayed.

$listbox.add_MouseUP({
    $maxY = $this.items.count * $this.itemHeight
    if ($_.y -le $maxY) {
        $this.SelectedIndex = $this.IndexFromPoint($_.X, $_.y)
        #do stuff here
    } 
    else {
        $this.clearselection()
    }
}

This will clear all selections if clicking on blank space, but will also prevent an item from being selected when clicking on blank space.