WPF Listbox 点击空白处取消选择

5
我有一个包含矩形的自定义项模板的WPF listbox。列表框中的每个项目都可以被选择(每次只能选择一个)。 我想添加一种行为,当用户点击不是项的位置(比如在listbox上的空白处,而不是项),所选项将变为未选中状态。
你有什么想法吗? 谢谢。
例如,一个简单的列表框:
item 1 item 2
我想要的行为是,当用户单击像素500(它是列表框的一部分但不属于任何项)时,当前选择的项将取消选择。

1
请编写一些代码,使您的问题更易于理解。 - Ahsan
你是如何确保列表框始终包含一个空白区域的? - Gayot Fow
4个回答

9
简单的解决方案是将一个属性与 ListBox.SelectedItem 属性进行数据绑定,并在需要清除选择时将其设置为 null
<ListBox ItemsSource="{Binding YourItems}" SelectedItem="{Binding SelectedItem}" 
    SelectionMode="Single" />

然后在代码中,你只需执行以下操作即可清除选择内容:
SelectedItem = null;

你什么时候会这样做呢?你可以将一个处理程序附加到Window或UI中的任何其他控件的PreviewMouseLeftButtonDown事件。在处理程序方法中,您可以进行命中测试以查看用户单击的项是什么:

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

查看VisualTreeHelper.HitTest Method (Visual, Point)获取更多关于这部分的帮助。

然后可能是类似这样的内容:

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

当然,有许多方法可以实现这个目标,但是你需要填写我留下的几个空白部分,但是你应该得到这个想法。

编辑 >>>

通用的GetParentOfType方法是一个自定义的扩展方法,它在名为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);
    }

    ...
}

谢谢,我采用了你的解决方案并从中创建了一个行为。效果很棒! - user2853648
为什么我找不到“GetParentOfType()”函数? - starkshang
@starkshang,这是因为它是一个自定义方法。我现在已经添加了它的代码。对于回复的延迟表示抱歉。 - Sheridan
@Sheridan,谢谢,我已经查过了,这是C#语法,我以前不知道。 - starkshang

0

我正在寻找解决这个问题的方法,但是要防止在单击空白处时选择列表框中的最后一项。我的问题略有不同,但是我想出了相同的解决方案,对我有效。

虽然我使用的是PowerShell而不是C#,但我仍在使用Windows窗体列表框控件,因此我认为这个想法是适用的。

此外,在我寻找解决方案时,我找不到任何关于PowerShell处理此问题的讨论,所以我来到了这里。

因此,我创建了一个变量maxY,并将列表项数乘以itemheight。

接下来,在mouse_up事件开始时,我只需检查鼠标单击的Y位置是否小于maxY变量。如果为真,则选择该项并运行您的代码;如果不是,则不执行任何操作。

我只能提供PowerShell的代码示例,但我认为这个想法已经表达清楚。

$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()
    }
}

如果在空白区域单击,这将清除所有选择,但也会防止在空白区域单击时选择项目。


0
为确保只选择一个项目,请将以下代码放入列表框中:
SelectionMode="Single"

然后对于未选择的情况,当单击某个地方时,您可以尝试检查这些事件

PreviewMouseLeftButtonUp
LostFocus()

敬礼,


0

对于 列表框中的每个项目都可以被选择(一次只能选择一个)。

您可以采用以下方法之一

1- 在选择后禁用该项。

2- 在后端维护一个列表,标记每个索引可选择或不可选择。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接