为什么WPF列表框会在鼠标按钮上更改选择而不是按钮?

Jor*_*Day 11 .net c# wpf xaml listbox

我之前从未注意到这一点,但是当鼠标停止时,WPF ListBox似乎更改了其SelectedItem,但尚未发布.作为一个简单的例子,只需创建一个包含多个ListBoxItem的简单ListBox,如下所示:

<ListBox>
  <ListBoxItem>Hello</ListBoxItem>
  <ListBoxItem>World</ListBoxItem>
  <ListBoxItem>ListBox</ListBoxItem>
  <ListBoxItem>Test</ListBoxItem>
</ListBox>
Run Code Online (Sandbox Code Playgroud)

启动你的应用程序,按下鼠标按钮(不要释放它!)并移动鼠标.SelectedItem将随着鼠标移动而改变.这说明了一个更大的问题(至少对我来说),一旦你按下鼠标就会设置ListBox的SelectedItem ,而不是在鼠标启动时设置.通常这不是问题,但在我的情况下,我想在我的ListBox中的项目上进行拖放操作,而不会明确选择项目.

我想我唯一的办法就是构建一个自定义的ItemsControl或Selector,其选择风格类似于ListBox,所以我的问题更多,为什么ListBox以这种方式工作?有没有人对此有任何见解?

Zir*_*iax 9

我个人更喜欢MVVM和附加属性来调整元素的行为.

此外,当绑定ItemsSource属性时,Tomas Kosar提出的解决方案似乎不起作用.

这是我目前使用的(C#7语法)

public static class SelectorBehavior
{
    #region bool ShouldSelectItemOnMouseUp

    public static readonly DependencyProperty ShouldSelectItemOnMouseUpProperty = 
        DependencyProperty.RegisterAttached(
            "ShouldSelectItemOnMouseUp", typeof(bool), typeof(SelectorBehavior), 
            new PropertyMetadata(default(bool), HandleShouldSelectItemOnMouseUpChange));

    public static void SetShouldSelectItemOnMouseUp(DependencyObject element, bool value)
    {
        element.SetValue(ShouldSelectItemOnMouseUpProperty, value);
    }

    public static bool GetShouldSelectItemOnMouseUp(DependencyObject element)
    {
        return (bool)element.GetValue(ShouldSelectItemOnMouseUpProperty);
    }

    private static void HandleShouldSelectItemOnMouseUpChange(
        DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is Selector selector)
        {
            selector.PreviewMouseDown -= HandleSelectPreviewMouseDown;
            selector.MouseUp -= HandleSelectMouseUp;

            if (Equals(e.NewValue, true))
            {
                selector.PreviewMouseDown += HandleSelectPreviewMouseDown;
                selector.MouseUp += HandleSelectMouseUp;
            }
        }
    }

    private static void HandleSelectMouseUp(object sender, MouseButtonEventArgs e)
    {
        var selector = (Selector)sender;

        if (e.ChangedButton == MouseButton.Left && e.OriginalSource is Visual source)
        {
            var container = selector.ContainerFromElement(source);
            if (container != null)
            {
                var index = selector.ItemContainerGenerator.IndexFromContainer(container);
                if (index >= 0)
                {
                    selector.SelectedIndex = index;
                }
            }
        }
    }

    private static void HandleSelectPreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
        e.Handled = e.ChangedButton == MouseButton.Left;
    }

    #endregion

}
Run Code Online (Sandbox Code Playgroud)

现在您可以将它应用于任何ListBox(或Selector派生类),例如

<ListBox ItemsSource="{Binding ViewModelItems}" 
    SelectedItem="{Binding SelectedViewModelItem}" 
    ui:SelectorBehavior.ShouldSelectItemOnMouseUp="True" />
Run Code Online (Sandbox Code Playgroud)

  • 基本上我喜欢这个解决方案。问题是,它仅适用于 **SingleSelection**-Mode。虽然这解决了作者的问题,但也许其他人可能对更通用的解决方案感兴趣。 (2认同)

Tom*_*sar 7

这可能有点偏离主题,但我只是遇到了类似的问题.我不想拖放但我想在MouseUp上的ListBox上选择项目而不是MouseDown.尽管Sheena伪代码可能会给出一些暗示,但在我找到正确的解决方案之前,它仍然需要一段时间.所以这是我解决问题的方法.

public class ListBoxSelectionItemChangedOnMouseUp : ListBox
{
    protected override void OnMouseUp(MouseButtonEventArgs e)
    {
        if (e.ChangedButton == MouseButton.Left)
        {
            DependencyObject obj = this.ContainerFromElement((Visual)e.OriginalSource);
            if (obj != null)
            {
                FrameworkElement element = obj as FrameworkElement;
                if (element != null)
                {
                    ListBoxItem item = element as ListBoxItem;
                    if (item != null && this.Items.Contains(item))
                    {
                        this.SelectedItem = item;
                    }
                }
            }
        }
    }

    protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
    {
        e.Handled = true;
    }
}
Run Code Online (Sandbox Code Playgroud)

我也想只选择鼠标左键.在拖放的情况下,必须在鼠标按下事件中保存所选项目,然后在鼠标按下事件中使用它.我希望这会对某人有所帮助.

  • thx的灵感.看到我的回答[这里](http://stackoverflow.com/a/25643836/911929) (2认同)