我有一个列表框,如果用户还没有完成某些任务,我想阻止更改ListBox的选择,这是我目前可以提供的最好的解释,在WinForms中曾经有选择更改,并且它具有可取消的事件争论,即使改变选择,我们也可以陷阱和取消。
我以为我会继承listbox并做一些事情,但内部所有Selector类中的功能都隐藏了,我可以在反射器中看到但是我无法继承和覆盖任何方法!!
答案 0 :(得分:3)
我从ListBox派生了一个类MyListBox,并添加了一个名为SelectionChanging的事件,它是可取消的事件。然后我在MyListBox中使用MyListBoxItem作为ItemContainer处理Preview Left Mouse Up事件并引发Selection Changing事件,取消值,我将事件标记为已处理,这会阻止新选择,并且它允许我通知用户执行某些操作。
答案 1 :(得分:1)
将IsSelected
绑定到视图模型类中的属性,并在属性的setter中处理大小写,例如:
public bool IsSelected
{
get { return _IsSelected; }
set
{
if (value && DisableSelection)
{
AlertUser();
}
else
{
_IsSelected = value;
}
OnPropertyChanged("IsSelected");
}
}
请注意,即使属性没有更改,也会引发PropertyChanged
事件,因为从视图的角度来看,它确实发生了变化。
答案 2 :(得分:0)
我知道这并没有直接回答你的问题,但在大多数情况下(我需要确信有理由不这样做),在完成选择标准之前,我根本无法控制。
这个简单的步骤消除了确定值已更改的大部分复杂性,以及是否为有效更改等。如果您允许编辑comboxbox(即键入的值),则会增加另一个级别复杂性。
否则,这是一个相关的讨论: How to prevent/cancel a combobox's value change in c#?
答案 3 :(得分:0)
一种解决方案是使ListBox和ListBoxItems无法调焦,直到您准备好让用户更改它们为止。这是一个快速模拟,完成了这个:
XAML:
<StackPanel>
<ListBox x:Name="LB">
<ListBoxItem Focusable="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=Focusable}" Content="item 1"/>
<ListBoxItem Focusable="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=Focusable}" Content="item 2"/>
<ListBoxItem Focusable="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=Focusable}" Content="item 3"/>
<ListBoxItem Focusable="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=Focusable}" Content="item 4"/>
<ListBoxItem Focusable="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=Focusable}" Content="item 5"/>
<ListBoxItem Focusable="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=Focusable}" Content="item 6"/>
</ListBox>
<Button Content="Lock/Unlock" Click ="Button_Click"/>
</StackPanel>
代码:
private void Button_Click(object sender, RoutedEventArgs e)
{
if (LB.Focusable == true)
LB.Focusable = false;
else
LB.Focusable = true;
}
答案 4 :(得分:0)
这有点像黑客,但我只是使用了listbox的PreviewMouseLeftButtonDown事件。
在处理程序中,我不得不问用户他们是否确定要离开。出于某种原因,在弹出消息框之后,无论您是否将e.handled标记为true,所选事件都不会触发,有关该消息框的内容。因此,如果用户确认导航,我将使用鼠标点击查找已单击的相应数据项(使用VisualTreeHelper循环,直到找到ListBoxItem),然后手动选择该项。如果用户选择不离开,只需将e.handled设置为false(尽管弹出一个消息框似乎具有相同的效果。)
答案 5 :(得分:0)
我有同样的需求(当不符合某些条件时,询问用户是否真的想要在单一选择 ListBox中更改所选项目)。单一选择很重要,否则代码会变得更复杂。我根据tempy的答案提出了我的解决方案,但遍历可视树似乎太麻烦了,所以我只是使用listBox.ItemContainerGenerator来询问ListBox项目鼠标是否超过其中任何一个,并采取相应的行动:
private void listBox_PreviewMouseDown(object sender, MouseButtonEventArgs e) {
if (CheckIfCurrentlySelectedItemCanBeDeselected())
// let things run normally
return;
var itemUnderMouse = GetListBoxItemUnderMouse(listBox);
// check if there is no item under mouse
// or if it is the currently selected item
if (itemUnderMouse == null || itemUnderMouse.Content == currentItem)
return;
// always set Handled and take care of changing selection manually
e.Handled = true;
if (MessageBox.Show("The selected value is not valid, change selection?", "", MessageBoxButton.YesNo) == MessageBoxResult.Yes) {
// change the value manually
lbArticles.SelectedItem = itemUnderMouse.Content;
}
}
private ListBoxItem GetListBoxItemUnderMouse(ListBox lb) {
foreach (object o in lb.Items) {
ListBoxItem lbi = lb.ItemContainerGenerator.ContainerFromItem(o) as ListBoxItem;
if (lbi != null && lbi.IsMouseOver) {
return lbi;
}
}
return null;
}