一次仅选择一项的多个 WPF 列表框
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12759507/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Multiple WPF ListBoxes with only one item selected at a time
提问by user1722960
I am using MVVM and am displaying two listboxes on one window. I am binding from both of those listboxes simultaneously to different fields call them A and B. A and B are then both modifying C. To make this work, I want to only have one item from the two listboxes IsSelected at once, so that A does not override C when B IsSelected. How can I restrict this?
我正在使用 MVVM 并在一个窗口上显示两个列表框。我同时从这两个列表框绑定到不同的字段,称为 A 和 B。然后 A 和 B 都在修改 C。为了完成这项工作,我只想一次从两个列表框 IsSelected 中获得一个项目,以便 A当 B IsSelected 时不覆盖 C。我怎样才能限制这个?
回答by Simon
I can think of a couple of ways to do this.
我可以想到几种方法来做到这一点。
One way is you could bind the ListBox.SelectedIndexof your 2 ListBoxes to change-notifying ViewModel properties.
一种方法是您可以将ListBox.SelectedIndex2 个 ListBox 中的绑定到更改通知 ViewModel 属性。
For example in your View:
例如在您的视图中:
<ListBox SelectedIndex="{Binding SelectedIndexA}">
<ListBoxItem Content="Item 1"/>
<ListBoxItem Content="Item 2"/>
</ListBox>
<ListBox SelectedIndex="{Binding SelectedIndexB}">
<ListBoxItem Content="Item 1"/>
<ListBoxItem Content="Item 2"/>
</ListBox>
And in your ViewModel:
在您的 ViewModel 中:
public int SelectedIndexA
{
get { return _selectedIndexA; }
set
{
_selectedIndexA = value;
_selectedIndexB = -1;
OnPropertyChanged("SelectedIndexB");
}
}
public int SelectedIndexB
{
get { return _selectedIndexB; }
set
{
_selectedIndexB = value;
_selectedIndexA = -1;
OnPropertyChanged("SelectedIndexA");
}
}
Another way would be with an attached property like 'GroupName' where you can group Selectors (ListBoxinherits from Selector) to ensure only one Selectorin the group has a selected item at any one time.
另一种方法是使用诸如“GroupName”之类的附加属性,您可以在其中对选择器(ListBox继承自Selector)进行分组,以确保Selector在任何时候组中只有一个具有所选项目。
For example:
例如:
public static class SingleSelectionGroup
{
public static readonly DependencyProperty GroupNameProperty =
DependencyProperty.RegisterAttached("GroupName", typeof(string), typeof(SingleSelectionGroup),
new UIPropertyMetadata(OnGroupNameChanged));
public static string GetGroupname(Selector selector)
{
return (string) selector.GetValue(GroupNameProperty);
}
public static void SetGroupName(Selector selector, string value)
{
selector.SetValue(GroupNameProperty, value);
}
private static void OnGroupNameChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
var selector = (Selector) dependencyObject;
if (e.OldValue != null)
selector.SelectionChanged -= SelectorOnSelectionChanged;
if (e.NewValue != null)
selector.SelectionChanged += SelectorOnSelectionChanged;
}
private static void SelectorOnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count == 0)
return;
var selector = (Selector) sender;
var groupName = (string) selector.GetValue(GroupNameProperty);
var groupSelectors = GetGroupSelectors(selector, groupName);
foreach (var groupSelector in groupSelectors.Where(gs => !gs.Equals(sender)))
{
groupSelector.SelectedIndex = -1;
}
}
private static IEnumerable<Selector> GetGroupSelectors(DependencyObject selector, string groupName)
{
var selectors = new Collection<Selector>();
var parent = GetParent(selector);
GetGroupSelectors(parent, selectors, groupName);
return selectors;
}
private static DependencyObject GetParent(DependencyObject depObj)
{
var parent = VisualTreeHelper.GetParent(depObj);
return parent == null ? depObj : GetParent(parent);
}
private static void GetGroupSelectors(DependencyObject parent, Collection<Selector> selectors, string groupName)
{
var childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
var selector = child as Selector;
if (selector != null && (string) selector.GetValue(GroupNameProperty) == groupName)
selectors.Add(selector);
GetGroupSelectors(child, selectors, groupName);
}
}
}
And in your View:
在您的视图中:
<ListBox my:SingleSelectionGroup.GroupName="Group A">
<ListBoxItem Content="Item 1 (Group A)"/>
<ListBoxItem Content="Item 2 (Group A)"/>
</ListBox>
<ListBox my:SingleSelectionGroup.GroupName="Group A">
<ListBoxItem Content="Item 1 (Group A)"/>
<ListBoxItem Content="Item 2 (Group A)"/>
</ListBox>
<ListBox my:SingleSelectionGroup.GroupName="Group B">
<ListBoxItem Content="Item 1 (Group B)"/>
<ListBoxItem Content="Item 2 (Group B)"/>
</ListBox>
<ListBox my:SingleSelectionGroup.GroupName="Group B">
<ListBoxItem Content="Item 1 (Group B)"/>
<ListBoxItem Content="Item 2 (Group B)"/>
</ListBox>
If you have to click an item twice before it is highlighted you can use a quick workaround like this:
如果您必须在突出显示之前单击项目两次,您可以使用如下快速解决方法:
<Style TargetType="ListBoxItem">
<Style.Triggers>
<EventTrigger RoutedEvent="GotKeyboardFocus">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="(ListBoxItem.IsSelected)">
<DiscreteBooleanKeyFrame KeyTime="00:00:00" Value="True" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
回答by Vishal
If anybody has used ListBox/ListView inside ItemsControl and has the following problem after using the above answer:
如果有人在 ItemsControl 中使用过 ListBox/ListView 并且在使用上述答案后出现以下问题:
- When you click on any Item in listbox1 the item is selected.
- When you click on any item in listbox2 the selected item of listbox1 is unselected but no item in listbox2 is selected.
- When you click again on any item in listbox2 the item is selected.
- 当您单击 listbox1 中的任何项目时,该项目被选中。
- 当您单击 listbox2 中的任何项目时,listbox1 的选定项目未选中,但 listbox2 中的任何项目都未选中。
- 当您再次单击 listbox2 中的任何项目时,该项目被选中。
Just add below xaml to the style of your ListBoxItem:
只需将下面的 xaml 添加到 ListBoxItem 的样式中:
<Style TargetType="ListBoxItem">
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="IsSelected" Value="True"></Setter>
</Trigger>
</Style.Triggers>
</Style>
Also, If anybody is getting the following error after using code in above answer:
另外,如果有人在使用上述答案中的代码后出现以下错误:
GroupName is already registered by Selector
Please change the third parameter typeof(......)in dependency property declaration to Name of your class.
请将third parameter typeof(......)依赖属性声明更改为Name of your class。

