如何在WPF中的ListBox中编写“选择更改”事件?

时间:2010-05-10 13:13:02

标签: wpf listbox selectionchanging

我有一个列表框,如果用户还没有完成某些任务,我想阻止更改ListBox的选择,这是我目前可以提供的最好的解释,在WinForms中曾经有选择更改,并且它具有可取消的事件争论,即使改变选择,我们也可以陷阱和取消。

我以为我会继承listbox并做一些事情,但内部所有Selector类中的功能都隐藏了,我可以在反射器中看到但是我无法继承和覆盖任何方法!!

6 个答案:

答案 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;
    }
相关问题