防止取消选择ListBox中最后选择的项目的最佳方法

时间:2013-06-24 13:04:18

标签: c# wpf listbox

我需要在wpf中实现ListBox控件的自定义行为。 想法是禁用取消选择最后选择的元素。根据用户用鼠标点击所选项目时的默认行为,按住ctrl键,选择消失。当用户在最后选择的项目上单击鼠标+ ctrl时,我需要实现一些逻辑以使列表框不执行任何操作。

我找到的唯一方法是订阅ListBox.SelectionChanged并执行以下操作:

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

但是这个解决方案并不适合我,因为在这种情况下,当ListBox.SelectedItem绑定到viewmodel属性时会发生一些不需要的调用。

伪调用堆栈(取消选择所选项目时):

  1. SelectedItem已更改为null

  2. listBox_SelectionChanged被称为

  3. SelectedItem设置为上一个值

  4. 我想要的只是步骤1和3不会发生。这很重要,因为当SelectedItem更改时,会启动一些长时间运行的异步操作。

    谢谢,任何建议都将不胜感激!

1 个答案:

答案 0 :(得分:1)

找到解决方案。在ListBox上处理PreviewMouseLeftButtonDown对我来说很好。作为附属财产。

顺便说一句:我可以以某种方式解决这个问题吗?

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