我需要一个在第一次点击时选择的列表框,在第二次点击时取消选择,这样任何时候都只能选择零个或一个项目。
当您按住crtl时,选择/取消选择在列表框中实现(使用SelectionMode =“Single”),但遗憾的是,我的所有用户都不可能知道这一点。
使用SelectionMode =“Multiple”,我们拥有我想要的确切功能,除了您可以选择多个项目...
更多背景: 我希望用户首先选择要登录的安装,然后提供凭据(以及其他一些选择)
为实现这一目标,我使用了一个包含扩展内容的列表框。为了帮助扩展,我在listboxitem的左侧创建了一个三角形,当你选择了列表框项目时,在未展开时指向右转,指向下方。
因此,首先用户看到安装列表,然后,当他通过选择它选择了他想要的项目时,listboxitem会扩展到他需要输入的其他信息。它非常好,而且运行良好,但测试报告他们希望第二次点击三角形以取消选择(从而折叠展开的部分)。而且我必须承认我点击了¤%&也是箭头,期待行动导致崩溃...... :-(
任何人都知道如何实现这一目标(最好没有代码)?
答案 0 :(得分:29)
执行此操作的常用方法是将SelectionMode
模式设置为Multiple
,然后取消选择SelectionChanged
事件中新选择的所有项目。
请参阅以下链接
这是一个执行此操作的附加行为,可以像这样使用
<ListBox local:ListBoxSelectionBehavior.ClickSelection="True"
...>
<强> ListBoxSelectionBehavior 强>
public static class ListBoxSelectionBehavior
{
public static readonly DependencyProperty ClickSelectionProperty =
DependencyProperty.RegisterAttached("ClickSelection",
typeof(bool),
typeof(ListBoxSelectionBehavior),
new UIPropertyMetadata(false, OnClickSelectionChanged));
public static bool GetClickSelection(DependencyObject obj)
{
return (bool)obj.GetValue(ClickSelectionProperty);
}
public static void SetClickSelection(DependencyObject obj, bool value)
{
obj.SetValue(ClickSelectionProperty, value);
}
private static void OnClickSelectionChanged(DependencyObject dpo,
DependencyPropertyChangedEventArgs e)
{
ListBox listBox = dpo as ListBox;
if (listBox != null)
{
if ((bool)e.NewValue == true)
{
listBox.SelectionMode = SelectionMode.Multiple;
listBox.SelectionChanged += OnSelectionChanged;
}
else
{
listBox.SelectionChanged -= OnSelectionChanged;
}
}
}
static void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count > 0)
{
ListBox listBox = sender as ListBox;
var valid = e.AddedItems[0];
foreach (var item in new ArrayList(listBox.SelectedItems))
{
if (item != valid)
{
listBox.SelectedItems.Remove(item);
}
}
}
}
}
答案 1 :(得分:11)
试试:
您使用ToggleButton作为详细内容的“扩展器”。 切换按钮的“IsChecked”属性可以绑定到项目的IsSelected属性
这里是代码:
<ListBox SelectionMode="Single">
<ListBox.ItemsSource>
<x:Array Type="{x:Type sys:String}">
<sys:String>test1</sys:String>
<sys:String>test2</sys:String>
<sys:String>test3</sys:String>
<sys:String>test4</sys:String>
<sys:String>test5</sys:String>
<sys:String>test6</sys:String>
</x:Array>
</ListBox.ItemsSource>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ToggleButton IsChecked="{Binding
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ListBoxItem}},
Path=IsSelected}"
>btn</ToggleButton>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
它是如何工作的: 在列表框中只能选择一个项目。当我们选择一个项目时,Toggler会被扩展,因为他的IsChecked被绑定到他的父ListBoxItem的ListBoxItem.IsSelected(ListBoxItem是一个围绕每个Item的内容的Control)。 由于selectionMode在选择另一个项目时是单一的,因此会发生以下情况:
如果实际选择的项目的切换器未被选中,则该项目通过绑定取消选择...
答案 2 :(得分:0)
我的解决方案是将ListBox SelectionMode设置为Multiple,在Click事件上添加方法 forbidSelectionButOne ,之后只允许选择一个项目,如下所示:
Private Sub forbidSelectionButOne(sender As Object, e As MouseButtonEventArgs)
Dim lv As ListView = TryCast(sender, ListView)
If lv IsNot Nothing Then
If lv.SelectedIndex <> getCausesListViewItemIndex(sender, e) Then
lv.SelectedIndex = getCausesListViewItemIndex(sender, e)
e.Handled = True
End If
lv.Focus()
End If
End Sub
帮助函数找到鼠标点击的ListViewItem:
Private Function getCausesListViewItemIndex(ByVal sender As Object, e As RoutedEventArgs) As Integer
Dim dep As DependencyObject = TryCast(e.OriginalSource, DependencyObject)
Do While dep IsNot Nothing AndAlso Not TypeOf (dep) Is ListViewItem
dep = VisualTreeHelper.GetParent(dep)
Loop
If dep Is Nothing Then
Return -1
Else
Dim lv As ListView = TryCast(sender, ListView)
If lv IsNot Nothing Then
Dim i As Integer = lv.ItemContainerGenerator.IndexFromContainer(dep)
Return i
Else
Return -1
End If
End If
End Function
答案 3 :(得分:0)
我允许我自己补充Fredrik对于UWP和.NET Framework 4.7的回答:
public static class ListBoxSelectionBehavior
{
public static readonly DependencyProperty ClickSelectionProperty =
DependencyProperty.RegisterAttached("ClickSelection",
typeof(bool),
typeof(ListBoxSelectionBehavior),
new PropertyMetadata(false, OnClickSelectionChanged));
public static bool GetClickSelection(DependencyObject obj)
{
return (bool)obj.GetValue(ClickSelectionProperty);
}
public static void SetClickSelection(DependencyObject obj, bool value)
{
obj.SetValue(ClickSelectionProperty, value);
}
private static void OnClickSelectionChanged(DependencyObject dpo, DependencyPropertyChangedEventArgs e)
{
if (dpo is ListBox listBox)
{
if ((bool)e.NewValue == true)
{
listBox.SelectionMode = SelectionMode.Multiple;
listBox.SelectionChanged += OnSelectionChanged;
}
else
{
listBox.SelectionChanged -= OnSelectionChanged;
}
}
}
static void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count > 0)
{
ListBox listBox = sender as ListBox;
var valid = e.AddedItems[0];
foreach (var item in new ArrayList(listBox.SelectedItems.ToArray()))
{
if (item != valid)
{
listBox.SelectedItems.Remove(item);
}
}
}
}
}
答案 4 :(得分:0)
在uwp应用中, 使用SelectionMode =“ Multiple”
private void MyListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (MyListBox.SelectedItems.Count <= 1)
{
// code related to SelectionChanged
}
while (MyListBox.SelectedItems.Count > 1)
{
MyListBox.SelectedItems.RemoveAt(0);
}
}
答案 5 :(得分:0)
再容易一点 只需添加带有SelectionMode =“ Multiple”
的标志组合 private bool _ignoreSelectionFlag = false;
private void LbHistory_OnSelectionChanged(object sender,SelectionChangedEventArgs e)
{
if (_ignoreSelectionFlag)
return;
if (e.AddedItems.Count > 0)
{
ListBox listBox = sender as ListBox;
var valid = e.AddedItems[0];
_ignoreSelectionFlag = true;
LbHistory.UnselectAll();
LbHistory.SelectedItems.Add(e.AddedItems[0]);
e.Handled = true;
_ignoreSelectionFlag = false;
}
}