代码之家  ›  专栏  ›  技术社区  ›  Akash Kava

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

  •  2
  • Akash Kava  · 技术社区  · 15 年前

    我有一个列表框,我想防止更改列表框的选择,如果用户没有完成某些任务,这是我现在能提供的最好的解释,在WinForms中,曾经有选择更改,它有可取消的事件论证,在这里,我们甚至可以陷阱和取消更改选择。

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

    6 回复  |  直到 15 年前
        1
  •  3
  •   Akash Kava    15 年前

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

        2
  •  1
  •   Robert Rossney    15 年前

    束缚 IsSelected 到视图模型类中的属性,并在属性的setter中处理该案例,例如:

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

    注意你提高了 PropertyChanged 事件,即使属性没有更改,因为从视图的角度看,它确实更改了。

        3
  •  0
  •   Community Mohan Dere    8 年前

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

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

    否则,这里有一个相关的讨论: How to prevent/cancel a combobox's value change in c#?

        4
  •  0
  •   Ben Collier    15 年前

    一种解决方案是,在准备好让用户更改列表框和列表框项之前,使它们不可聚焦。下面是一个快速的模型,完成了这一点:

    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;
        }
    
        5
  •  0
  •   tempy    15 年前

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

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

        6
  •  0
  •   TheDark    10 年前

    我也有同样的需求(询问用户是否真的想在 单一选择 列表框)。单一选择很重要,否则代码会变得更复杂。我的解决方案是基于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;
        }
    
    推荐文章