【问题标题】:Click and drag selection box in WPF在 WPF 中单击并拖动选择框
【发布时间】:2010-12-22 17:30:39
【问题描述】:

是否可以在 WPF 中实现鼠标单击和拖动选择框。是否应该通过简单地绘制一个矩形,计算其点的坐标并评估该框内其他对象的位置来完成?还是有其他方法?

您能否提供一些示例代码或链接?

【问题讨论】:

  • 对于绘图来说,它并不那么简单,因为您可能希望将选择框绘制在所有内容之上,并且您的对象可能是 UIElements 本身。您需要使用装饰器。
  • 帕维尔,谢谢你的小费。我将深入探讨装饰器主题。如果你能再给我一些关于为此目的使用装饰器的信息(只是学习方向),我会很感激的。无论如何,谢谢你。

标签: c# wpf mouse selection drag


【解决方案1】:

您可以通过添加 InkCanvas 并将其 EditingMode 设置为 Select 来轻松获得此功能。虽然它主要用于 Tablet PC 墨水收集和渲染,但它很容易用作基本的设计器界面。

<Window Width="640" Height="480" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
    <InkCanvas EditingMode="Select">
        <Button Content="Button" Width="75" Height="25"/>
        <Button Content="Button" Width="75" Height="25"/>
    </InkCanvas>
</Window>

【讨论】:

  • 嗨乔希,谢谢。我一定会研究 InkCanvas 功能。请告诉我,你的意思是在 InkCanvas 上绘制一个矩形会自动匹配它下面的所有对象并允许将它们选中?
  • 不幸的是,我似乎找不到让 InkCanvas 使用矩形选择的简单方法。它使用套索选择。但是,是的,您将元素放入其中,您可以使用套索选择它们并拖动、调整大小等。您可以通过在 InkCanvas 上设置属性来禁用拖动/调整大小功能。
  • 我将您的代码放在一个测试 WPF 项目中并使用了一段时间。是的,它似乎有很多有趣的功能,包括你所说的——套索、拖动、调整大小。我不知道。谢谢你。但是,你知道,我没想到找到关于选择框的信息会这么难。老实说,我希望它属于标准的预定义功能,比如在画布上放置按钮.. :)
  • InkCanvas 在 M. MacDonald 所著的“Pro WPF in C# 2010”一书中进行了描述,p。 96. 仅供参考。
【解决方案2】:

这是我过去用来绘制拖动选择框的简单技术的示例代码。

XAML:

<Window x:Class="DragSelectionBox.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300"
    >
    <Grid
        x:Name="theGrid"
        MouseDown="Grid_MouseDown"
        MouseUp="Grid_MouseUp"
        MouseMove="Grid_MouseMove"
        Background="Transparent"
        >
        <Canvas>
            <!-- This canvas contains elements that are to be selected -->
        </Canvas>
        
        <Canvas>
            <!-- This canvas is overlaid over the previous canvas and is used to 
                place the rectangle that implements the drag selection box. -->
            <Rectangle
                x:Name="selectionBox"
                Visibility="Collapsed"
                Stroke="Black"
                StrokeThickness="1"
                />
        </Canvas>
    </Grid>
</Window>

C#:

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
    }

    bool mouseDown = false; // Set to 'true' when mouse is held down.
    Point mouseDownPos; // The point where the mouse button was clicked down.

    private void Grid_MouseDown(object sender, MouseButtonEventArgs e)
    {
        // Capture and track the mouse.
        mouseDown = true;
        mouseDownPos = e.GetPosition(theGrid);
        theGrid.CaptureMouse();

        // Initial placement of the drag selection box.         
        Canvas.SetLeft(selectionBox, mouseDownPos.X);
        Canvas.SetTop(selectionBox, mouseDownPos.Y);
        selectionBox.Width = 0;
        selectionBox.Height = 0;
        
        // Make the drag selection box visible.
        selectionBox.Visibility = Visibility.Visible;
    }

    private void Grid_MouseUp(object sender, MouseButtonEventArgs e)
    {
        // Release the mouse capture and stop tracking it.
        mouseDown = false;
        theGrid.ReleaseMouseCapture();
        
        // Hide the drag selection box.
        selectionBox.Visibility = Visibility.Collapsed;
        
        Point mouseUpPos = e.GetPosition(theGrid);
        
        // TODO: 
        //
        // The mouse has been released, check to see if any of the items 
        // in the other canvas are contained within mouseDownPos and 
        // mouseUpPos, for any that are, select them!
        //
    }

    private void Grid_MouseMove(object sender, MouseEventArgs e)
    {
        if (mouseDown)
        {
            // When the mouse is held down, reposition the drag selection box.
            
            Point mousePos = e.GetPosition(theGrid);

            if (mouseDownPos.X < mousePos.X)
            {
                Canvas.SetLeft(selectionBox, mouseDownPos.X);
                selectionBox.Width = mousePos.X - mouseDownPos.X;
            }
            else
            {
                Canvas.SetLeft(selectionBox, mousePos.X);
                selectionBox.Width = mouseDownPos.X - mousePos.X;
            }

            if (mouseDownPos.Y < mousePos.Y)
            {
                Canvas.SetTop(selectionBox, mouseDownPos.Y);
                selectionBox.Height = mousePos.Y - mouseDownPos.Y;
            }
            else
            {
                Canvas.SetTop(selectionBox, mousePos.Y);
                selectionBox.Height = mouseDownPos.Y - mousePos.Y;
            }
        }
    }
}

我写了一篇关于这个的文章:

https://www.codeproject.com/Articles/148503/Simple-Drag-Selection-in-WPF

【讨论】:

  • 天才!将 StrokeDashArray="2,1" 添加到您的矩形以获得虚线选择器。
  • 很好的解决方案。我所做的一项改进是在 Point mousePos = e.GetPosition(theGrid); 之后添加以下代码在 Grid_MouseMove() 中将选择矩形约束到父 Grid: if (mousePos.X theGrid.ActualWidth) mousePos.X = theGrid.ActualWidth; if (mousePos.Y theGrid.ActualHeight) mousePos.Y = theGrid.ActualHeight;
  • 在这种情况下使用 VisualTreeHelper.HitTest(theGrid, mousePos) 更容易。
  • 效果很好!不过,我在选择和“裁剪”图像时遇到了麻烦,这是因为图像的 DPI 不一定与显示器的 DPI 匹配,从而产生“偏移”或“偏移”。我只是在 Image 元素中添加了:Width="{Binding Source.PixelWidth,RelativeSource={RelativeSource Self}}" Height="{Binding Source.PixelHeight,RelativeSource={RelativeSource Self}}" 以自动标准化 DPI。跨度>
  • 人们还在使用 WPF?!哇,我回答这个问题已经10年了。你应该看看我写的这篇文章:codeproject.com/Articles/148503/Simple-Drag-Selection-in-WPF
【解决方案3】:

MouseDown 逻辑:

MouseRect.X = mousePos.X >= MouseStart.X ? MouseStart.X : mousePos.X;
MouseRect.Y = mousePos.Y >= MouseStart.Y ? MouseStart.Y : mousePos.Y;
MouseRect.Width = Math.Abs(mousePos.X - MouseStart.X);
MouseRect.Height = Math.Abs(mousePos.Y - MouseStart.Y);

【讨论】:

    【解决方案4】:

    该项目创建了一个自定义MultiSelector,它支持多种选择方法,包括矩形“套索”样式:

    Developing a MultiSelector by Teofil Cobzaru

    这里复制太长了。 IIRC 设计的关键元素是创建一个自定义的ItemContainer,它知道如何与其MultiSelector 父级交互。这类似于ListBoxItem / ListBox

    这可能不是最简单的方法,但是如果您已经在使用某种类型的 ItemsControl 来托管可能需要选择的项目,那么它可以很容易地适应该设计。

    【讨论】:

      猜你喜欢
      • 2015-04-08
      • 2012-09-24
      • 2015-05-20
      • 1970-01-01
      • 1970-01-01
      • 2021-04-10
      • 1970-01-01
      • 2013-06-30
      • 2015-10-28
      相关资源
      最近更新 更多