【问题标题】:Disabling "Drag Selection" on ListBox禁用 ListBox 上的“拖动选择”
【发布时间】:2011-11-09 15:07:55
【问题描述】:

Winforms 的ListBox 似乎有一个奇怪的行为。当我将SelectionMode 设置为一个时,我希望我可以单击一个项目,它会被选中。这是正确的,但是如果我单击一个项目,上下拖动列表,选择就会改变。

现在,这没什么大不了的,只是我需要在一些控件之间执行拖放操作。因此,当他们选择一个项目并将其拖到列表中时,一个新选择的项目实际上是它注册为拖动的项目,并且错误的项目被发送过来。

因此,我通过在 mousedown 上保存对所选项目的引用来进一步包扎它,但这最终导致用户体验不佳。我的用户将一个项目拖到另一个列表框,这确实有效,但是原始列表框不再选择“正确”的项目,并且他们对实际将哪个项目拖放到第二个控件上感到困惑。

那么,有没有办法改变这种行为呢?我希望在 MouseDown 处选择一个项目,忽略 MouseUp 部分。仅仅消费事件似乎是不够的,我宁愿不必重写 ListBox(我们必须为正在创建的任何新类编写文档)。

【问题讨论】:

    标签: c# winforms listbox


    【解决方案1】:

    我猜如果你打电话给DoDragDrop,这种行为就会消失。 Windows 在拖放模式下不会发送 MouseOver 消息。

    propper 拖放示例:

        private void listBox_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) 
        {
            // Get the index of the item the mouse is below.
            indexOfItemUnderMouseToDrag = listBox.IndexFromPoint(e.X, e.Y);
    
            if (indexOfItemUnderMouseToDrag != ListBox.NoMatches) {
    
                // Remember the point where the mouse down occurred. The DragSize indicates
                // the size that the mouse can move before a drag event should be started.                
                Size dragSize = SystemInformation.DragSize;
    
                // Create a rectangle using the DragSize, with the mouse position being
                // at the center of the rectangle.
                dragBoxFromMouseDown = new Rectangle(new Point(e.X - (dragSize.Width /2),
                                                               e.Y - (dragSize.Height /2)), dragSize);
            } else
                // Reset the rectangle if the mouse is not over an item in the ListBox.
                dragBoxFromMouseDown = Rectangle.Empty;
    
        }
    
        private void listBox_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e) {
            // Reset the drag rectangle when the mouse button is raised.
            dragBoxFromMouseDown = Rectangle.Empty;
        }
    
        private void listBox_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) 
        {
            if ((e.Button & MouseButtons.Left) == MouseButtons.Left) {
    
                // If the mouse moves outside the rectangle, start the drag.
                if (dragBoxFromMouseDown != Rectangle.Empty && 
                    !dragBoxFromMouseDown.Contains(e.X, e.Y)) 
                {
                        DragDropEffects dropEffect = listBox.DoDragDrop(listBox.Items[indexOfItemUnderMouseToDrag], DragDropEffects.All | DragDropEffects.Link);
    
                        // If the drag operation was a move then remove the item.
                        if (dropEffect == DragDropEffects.Move) {                        
                            listBox.Items.RemoveAt(indexOfItemUnderMouseToDrag);
    
                            // Selects the previous item in the list as long as the list has an item.
                            if (indexOfItemUnderMouseToDrag > 0)
                                listBox.SelectedIndex = indexOfItemUnderMouseToDrag -1;
    
                            else if (ListDragSource.Items.Count > 0)
                                // Selects the first item.
                                listBox.SelectedIndex =0;
                        }
                    }
                }
            }
        }
    

    ...和SelectedIndexChanged 仍然有效!

    【讨论】:

    • 还有另一个问题——我需要处理拖放和SelectedIndexChanged 事件来显示信息。因此,我使用了旧的计时器技巧(在 MouseDown 上启动计时器,在 MouseUp 上清除它,如果它滴答作响,则使用 DoDragDrop())。我怀疑你是对的;如果我立即调用 DoDragDrop,它将避免选择模式。
    • 同时处理拖放和SelectedIndexChanged都不是问题。当您单击项目时,选择索引会更改并触发右事件。然后在MouseMove 中检查当前光标位置离鼠标下点有多远,并在适当的时候调用DoDragDrop。看看我上面的帖子 - 我添加了一个如何使拖放正常工作的示例。
    猜你喜欢
    • 1970-01-01
    • 2018-08-09
    • 1970-01-01
    • 1970-01-01
    • 2014-07-13
    • 1970-01-01
    • 2013-02-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多