Reputation: 381
I need to implement custom behavior for ListBox control in wpf. The idea is to disable unselect last selected element. According to default behavior when user clicks on selected item with mouse, holding ctrl key pressed, the selection disappears. I need to implement some logic to make listbox do nothing when user click mouse+ctrl on last selected item.
The only approach i have found is to subscribe to ListBox.SelectionChanged and do something like this:
private static void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var listBox = sender as ListBox;
if (listBox != null && e.RemovedItems != null && e.RemovedItems.Count == 1)
{
var removed = e.RemovedItems[0];
if (listBox.SelectedItems.Count == 0)
{
if (listBox.SelectionMode == System.Windows.Controls.SelectionMode.Single)
{
listBox.SelectedItem = removed;
}
else
{
listBox.SelectedItems.Add(removed);
}
e.Handled = true;
}
}
}
but this solution is not suitable for me, because in this case some undesired calls happens when ListBox.SelectedItem is bound to viewmodel property.
pseudo callstack (when unselecting selected item):
SelectedItem changed to null
listBox_SelectionChanged is called
SelectedItem is set to previous value
All i want is that steps 1 and 3 don`t ever happen. It is important because when SelectedItem changes some long-running async operation is started.
Thank you, any advices would be appreciated!
Upvotes: 2
Views: 1692
Reputation: 381
Found solution. Processing PreviewMouseLeftButtonDown on ListBox works fine for me. Made as attached property.
BTW: Can i somehow close the issue?
public static class ListBoxAttachedProperties
{
public static readonly DependencyProperty DisableUnselectLast =
DependencyProperty.RegisterAttached(
"DisableUnselectLast", typeof(bool), typeof(ListBox),
new PropertyMetadata(false, DisableUnselectLastChangedCallback));
public static bool GetDisableUnselectLast(DependencyObject d)
{
return (bool)d.GetValue(DisableUnselectLast);
}
public static void SetDisableUnselectLast(DependencyObject d, bool value)
{
d.SetValue(DisableUnselectLast, value);
}
private static void DisableUnselectLastChangedCallback(
DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!(d is ListBox))
{
return;
}
var selector = d as ListBox;
bool oldValue = (bool)e.OldValue;
bool newValue = (bool)e.NewValue;
if (oldValue == newValue)
{
return;
}
if (oldValue == false)
{
selector.PreviewMouseLeftButtonDown += listBox_PreviewMouseLeftButtonDown;
}
else
{
selector.PreviewMouseLeftButtonDown -= listBox_PreviewMouseLeftButtonDown;
}
}
private static void listBox_PreviewMouseLeftButtonDown(
object sender, System.Windows.Input.MouseButtonEventArgs e)
{
var listBox = sender as ListBox;
if (listBox != null && listBox.SelectedItems.Count == 1)
{
UIElement container = listBox.ItemContainerGenerator
.ContainerFromItem(listBox.SelectedItems[0]) as UIElement;
if (container != null)
{
var pos = e.GetPosition(container);
var result = VisualTreeHelper.HitTest(container, pos);
if (result != null)
{
e.Handled = true;
}
}
}
}
}
Upvotes: 1