如何对“选择更改”进行编程WPF 中列表框的事件?

发布于 2024-09-01 03:15:21 字数 188 浏览 11 评论 0原文

我有一个列表框,如果用户尚未完成某些任务,我想阻止更改列表框的选择,这是我此时可以提供的最佳解释,在 WinForms 中曾经有选择更改,并且具有可取消的事件争论,其中我们甚至可以捕获并取消更改选择。

我以为我会继承列表框并做一些事情,但在内部 Selector 类中的所有功能都被隐藏,我可以在反射器中看到这些功能,但我无法继承和重写任何方法!

I have a listbox and I want to prevent changing of ListBox's selection if user has not finished certain tasks, this is the best explanation i can provide at this time, in WinForms there used to be selection changing and it has cancellable event arguement, where in we could trap and cancel even of changing the selection.

I thought I will inherit listbox and do something but internally all functionalities in Selector class are hidden that I can see in reflector but there is no way i can inherit and override any methods !!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

谜泪 2024-09-08 03:15:21

我从 ListBox 派生了一个 MyListBox 类,并添加了名为 SelectionChanging 的事件,该事件是可取消的事件。然后我使用 MyListBoxItem 作为 MyListBox 中的 ItemContainer,它处理预览鼠标左键向上事件并引发选择更改事件,在取消值时,我将事件标记为已处理,这会阻止新的选择,并允许我通知用户执行某些操作。

I derived a class MyListBox from ListBox and added event called SelectionChanging which is cancellable event. Then I used MyListBoxItem as ItemContainer in MyListBox which handles Preview Left Mouse Up event and raises Selection Changing event, on cancel value, I mark event as handled, which prevents new selection as well as it allows me to notify user to do someting.

感情旳空白 2024-09-08 03:15:21

IsSelected 绑定到视图模型类中的属性,并在属性的 setter 中处理这种情况,例如:

public bool IsSelected
{
   get { return _IsSelected; }
   set
   {
       if (value && DisableSelection)
       {
          AlertUser();
       }
       else
       {
          _IsSelected = value;
       }
       OnPropertyChanged("IsSelected");
   }
}

请注意,即使该属性没有发生,您也会引发 PropertyChanged 事件变化,因为从视图的角度来看它确实发生了变化。

Bind IsSelected to a property in your view model class, and handle the case in the property's setter, e.g.:

public bool IsSelected
{
   get { return _IsSelected; }
   set
   {
       if (value && DisableSelection)
       {
          AlertUser();
       }
       else
       {
          _IsSelected = value;
       }
       OnPropertyChanged("IsSelected");
   }
}

Note that you raise the PropertyChanged event even if the property didn't change, because from the view's perspective it actually did change.

离鸿 2024-09-08 03:15:21

我知道这并不能直接回答您的问题,但在大多数情况下(我需要确信不这样做的原因),在满足选择标准之前我根本无法进行控制。

这个简单的步骤消除了确定值已更改以及是否是有效更改等的大部分复杂性。如果允许编辑组合框(即输入的值),则会增加另一级复杂性。

否则,这里有一个相关的讨论:
如何在 C# 中防止/取消组合框的值更改?

I know this doesn't directly answer your question, but in most cases (I'd need to be convinced of a reason not to), I would simply not enable to control until the criteria for selection is met.

This simple step removes most of the complexity of figuring out that the value changed, and if it was a valid change, etc. If you allow the comboxbox to be edited (i.e. a value typed in), that adds another level of complexity.

Otherwise, here is a related discussion:
How to prevent/cancel a combobox's value change in c#?

謸气贵蔟 2024-09-08 03:15:21

一种解决方案是使 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;
    }

One solution would be to make the ListBox and ListBoxItems not focusable until you are ready for the user to change them. Here is a quick mock-up that accomplished this:

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>

Code:

   private void Button_Click(object sender, RoutedEventArgs e)
    {
        if (LB.Focusable == true)
            LB.Focusable = false;
        else
            LB.Focusable = true;
    }
画离情绘悲伤 2024-09-08 03:15:21

这有点黑客行为,但我只是使用了列表框的 PreviewMouseLeftButtonDown 事件。

在处理程序中,我必须询问用户是否确定要离开。由于某种原因,弹出消息框后,无论您是否将 e.handled 标记为 true,所选事件都不会触发,这与该消息框有关。因此,如果用户确认导航,我将使用鼠标单击来查找单击的相应数据项(使用 VisualTreeHelper 循环,直到找到 ListBoxItem),然后手动选择该项目。如果用户选择不离开,只需将 e.handled 设置为 false(尽管弹出消息框似乎具有相同的效果。)

This is a bit of a hack, but I just used the listbox's PreviewMouseLeftButtonDown event.

In the handler, I had to ask the user if they were sure they want to navigate away. For some reason, after popping up a messagebox, regardless of whether you mark e.handled as true or not, the selected event will not fire, something about that messagebox. So, if the user confirms the navigation, I would use the mouseclick to find the corresponding dataitem that got clicked on (loop with VisualTreeHelper until you find a ListBoxItem) and then select that item manually. If the user chooses not to navigate away, just set e.handled to false (though popping up a messagebox seems to have an identical effect.)

不再见 2024-09-08 03:15:21

当某些条件不满足时,我有同样的需求(询问用户是否真的想更改单选列表框中的所选项目)。单选很重要,否则代码会变得更加复杂。我的解决方案基于 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;
    }

I had the same need (ask the user if he really wants to change the selected item in a single selection ListBox) when certain criteria are not met. Being single selection is important, otherwise the code gets more complicated. I based my solution off of tempy's answer, but traversing the visual tree seemed like too much trouble, so I just used the listBox.ItemContainerGenerator to ask the ListBox items if the mouse is over any of them, and act accordingly:

    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;
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文