代码之家  ›  专栏  ›  技术社区  ›  Mark Ingram

将列表框选择更改为切换选择的最佳方式

  •  1
  • Mark Ingram  · 技术社区  · 16 年前

    我有一个列表框控件,我想将其更改为具有切换选择。即,单击一个项目即可选择它,再次单击则取消选择它。此外,单击列表中的另一个项目应执行默认操作,即取消选择上一个项目并选择新项目。

    实现这一目标的最佳方式是什么?

    5 回复  |  直到 16 年前
        1
  •  2
  •   Sacha Bruttin    16 年前

    你想要的是一个单选按钮列表。您可以通过创建ItemDataTemplate并在其中放置RadioButton来创建一个模板。然后,您可以修改RadioButton的模板,使其看起来像一个按钮。

        2
  •  0
  •   Bijington    16 年前

    我会保留标准的列表框,这样你就可以保留你想要的默认行为,那么对于取消选择一个项目,你能在鼠标按下事件中处理它吗?即使用这样的东西:

    Point newPoint = e.GetPosition(backgroundImage);
    
    HitTestResult result = VisualTreeHelper.HitTest(this, newPoint);
    
    if (result.VisualHit is ListBoxItem)
    

    我不确定这是否是最好的方法,我唯一的另一种方法是从标准窗口控件派生我自己的列表框,并添加一个依赖属性,以允许我处理样式中的取消选择。如果你想采用这种方法,我也不应该删除你想要保留的默认行为,我使用这种方法创建了一个列表框,在文本旁边显示图像。

    如果你需要任何关于从哪里开始的指示,那就喊我一声。

        3
  •  0
  •   Mark Ingram    16 年前

    我通过稍微创建两个自定义类ToggleList&切换ListBoxItem。有几个方便的覆盖(ToggleListView中最重要的是创建ListBoxItem的覆盖)。

    从那里,很容易处理点击同一项目两次,或按空格键/回车键。这两个类都有40行代码,运行良好。

        4
  •  0
  •   dahvyd    13 年前

    万一有人感兴趣,我找到了一个不同的解决方案,对我来说效果很好。我设置了 ListBox.SelectionMode Multiple 并按如下方式处理MouseDown事件:

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

    其中listBox是父列表框控件。它确保在处理系统MouseDown事件处理程序之前取消选择所有列表框项,从而允许切换相同列表框项的选择状态。

        5
  •  0
  •   Insert Clever Username    5 年前

    我开始寻找一种“内置”的方式来做到这一点。当我看到没有答案,并注意到这里有我不太喜欢的答案时,我想我会发布我认为最好的方法。

    这个答案与 Bijington 的答案 我只是在列表框中添加了一个PreviewMouseDown处理程序

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

    然后在代码中

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

    然后我认为把它变成一个附加属性会很好,所以这里有一些伪代码来解释如何做到这一点。..

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

    然后在代码中:

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

    相关信息: