添加一个绘图面板
项目按右键添加类DrawingPanel
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Drawing
{
class DrawingPanel :Panel
{
//所有图形
private List<Visual> visuals = new List<Visual>();
private List<DrawingVisual> hits=new List<DrawingVisual>();
protected override Visual GetVisualChild(int index)
{
return visuals[index];
}
protected override int VisualChildrenCount
{
get
{
return visuals.Count;
}
}
public void addVisuals(Visual visual)
{
visuals.Add(visual);
base.AddVisualChild(visual);
base.AddLogicalChild(visual);
}
public void DeleteVisual(Visual visual)
{
visuals.Remove(visual);
base.RemoveVisualChild(visual);
base.RemoveLogicalChild(visual);
}
public DrawingVisual GetVisual(Point point)
{
HitTestResult hitTestResult = VisualTreeHelper.HitTest(this,point);
return hitTestResult.VisualHit as DrawingVisual;
}
//
public List<DrawingVisual> GetVisuals(Geometry geometry)
{
hits.Clear();
GeometryHitTestParameters parameters = new GeometryHitTestParameters(geometry);
HitTestResultCallback callback = new HitTestResultCallback(this.HitTestResultCallback);
VisualTreeHelper.HitTest(this, null, callback, parameters);
return hits;
}
//HitTest回调函数
private HitTestResultBehavior HitTestResultCallback(HitTestResult result)
{
GeometryHitTestResult geometryHitTest = (GeometryHitTestResult)result;
DrawingVisual visual = geometryHitTest.VisualHit as DrawingVisual;
if (visual != null && geometryHitTest.IntersectionDetail == IntersectionDetail.FullyInside)
{
hits.Add(visual);
}
return HitTestResultBehavior.Continue;
}
}
}
然后是在窗口中使用
以下是布局VisualLayer.xmal代码(项目按右键-WPF项目-窗口)
<Window x:Class="WpfApp1.VisualLayer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
xmlns:local1="clr-namespace:Drawing"
mc:Ignorable="d"
Title="VisualLayer" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions >
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<ToolBarTray Orientation="Vertical">
<ToolBar>
<RadioButton Margin="0,3" Name="cmdSelectMove">
<StackPanel>
<Image Source="pointer.png" Width="35" Height="35"></Image>
<TextBlock>Select/Move</TextBlock>
</StackPanel>
</RadioButton>
<RadioButton Margin="0,3" IsChecked="True" Name="cmdAdd">
<StackPanel>
<Rectangle Width="30" Height="30" Stroke="SteelBlue" StrokeThickness="3" Fill="AliceBlue">
</Rectangle>
<TextBlock>Add Square</TextBlock>
</StackPanel>
</RadioButton>
<RadioButton Margin="0,3" Name="cmdDelete">
<StackPanel>
<Path Stroke="SteelBlue" StrokeThickness="4" StrokeEndLineCap="Round" Fill="Red" HorizontalAlignment="Center">
<Path.Data>
<GeometryGroup>
<PathGeometry>
<PathFigure StartPoint="0,0">
<LineSegment Point="18,18"></LineSegment>
</PathFigure>
<PathFigure StartPoint="0,18">
<LineSegment Point="18,0"></LineSegment>
</PathFigure>
</PathGeometry>
</GeometryGroup>
</Path.Data>
</Path>
<TextBlock> Delete Square</TextBlock>
</StackPanel>
</RadioButton>
<RadioButton Margin="0,3" Name="cmdSelecMultipe" >
<StackPanel>
<Image Source="pointer.png" Width="35" Height="35"></Image>
<TextBlock>Select Multiple</TextBlock>
</StackPanel>
</RadioButton>
</ToolBar>
</ToolBarTray>
<Border Grid.Column="1" Margin="3" BorderBrush="SteelBlue" BorderThickness="1">
<local1:DrawingPanel x:Name="drawingSurface" Background="White" ClipToBounds="True" MouseLeftButtonDown="drawingSurface_MouseLeftButtonDown"
MouseLeftButtonUp="drawingSurface_MouseLeftButtonUp"
MouseMove="drawingSurface_MouseMove">
</local1:DrawingPanel>
</Border>
</Grid>
</Window>
VisualLayer.xaml.cs代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace WpfApp1
{
/// <summary>
/// VisualLayer.xaml 的交互逻辑
/// </summary>
public partial class VisualLayer : Window
{
private Brush drawingBrush = Brushes.AliceBlue;
private Brush selectedDrawingBrush = Brushes.LightGoldenrodYellow;
private Pen drawingPen = new Pen(Brushes.SteelBlue, 3);
private Size squareSize = new Size(30, 30);
private DrawingVisual drawingVisual;
private Vector clickOffset;
private bool isDragging;
private DrawingVisual selectedVisual;
private bool isMultiSelecting = false;
private Point selectionSquareTopLeft;
private Brush selectionSquareBrush = Brushes.Transparent;
private Pen selectionSquarePen = new Pen(Brushes.Black, 2);
private DrawingVisual selectionSquare;
public VisualLayer()
{
InitializeComponent();
DrawingVisual v = new DrawingVisual();
DrawingSquare(v, new Point(10,10), false);
}
private void DrawingSquare(DrawingVisual v,Point topLeftCorner,bool isSelected)
{
using(DrawingContext dc = v.RenderOpen())
{
Brush brush = drawingBrush;
if (isSelected) brush = selectedDrawingBrush;
dc.DrawRectangle(brush, drawingPen, new Rect(topLeftCorner, squareSize));
}
}
private void drawingSurface_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Point pointClicked = e.GetPosition(drawingSurface);
if (cmdAdd.IsChecked==true)
{
DrawingVisual drawingVisual = new DrawingVisual();
DrawingSquare(drawingVisual, pointClicked, false);
drawingSurface.addVisuals(drawingVisual);
}
else if (cmdDelete.IsChecked == true)
{
DrawingVisual drawingVisual = drawingSurface.GetVisual(pointClicked);
if (drawingVisual != null) drawingSurface.DeleteVisual(drawingVisual);
}
else if (cmdSelectMove.IsChecked == true)
{
DrawingVisual visual = drawingSurface.GetVisual(pointClicked);
if (visual != null)
{
Point topLeftCorner = new Point(
visual.ContentBounds.TopLeft.X + drawingPen.Thickness / 2,
visual.ContentBounds.TopLeft.Y + drawingPen.Thickness / 2);
DrawingSquare(visual, topLeftCorner, true);
clickOffset = topLeftCorner - pointClicked;
isDragging = true;
if (selectedVisual != null && selectedVisual != visual)
{
// The selection has changed. Clear the previous selection.
ClearSelection();
}
selectedVisual = visual;
}
} else if (cmdSelecMultipe.IsChecked == true)
{
selectionSquare = new DrawingVisual();
drawingSurface.addVisuals(selectionSquare);
selectionSquareTopLeft = pointClicked;
isMultiSelecting = true;
// Make sure we get the MouseLeftButtonUp event even if the user
// moves off the Canvas. Otherwise, two selection squares could be drawn at once.
drawingSurface.CaptureMouse();
}
}
private void ClearSelection()
{
Point topLeftCorner = new Point(
selectedVisual.ContentBounds.TopLeft.X + drawingPen.Thickness / 2,
selectedVisual.ContentBounds.TopLeft.Y + drawingPen.Thickness / 2);
DrawingSquare(selectedVisual, topLeftCorner, false);
selectedVisual = null;
}
private void drawingSurface_MouseMove(object sender, MouseEventArgs e)
{
if (isDragging)
{
Point pointDragged=e.GetPosition(drawingSurface)+clickOffset;
DrawingSquare(selectedVisual, pointDragged, true);
}
else if(isMultiSelecting)
{
Point pointDragged = e.GetPosition(drawingSurface);
DrawSelectionSquare(selectionSquareTopLeft, pointDragged);
}
}
private void DrawSelectionSquare(Point point1, Point point2)
{
selectionSquarePen.DashStyle = DashStyles.Dash;
using(DrawingContext dc= selectionSquare.RenderOpen())
{
dc.DrawRectangle(selectionSquareBrush, selectionSquarePen,
new Rect(point1, point2));
}
}
private void drawingSurface_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
isDragging = false;
if (isMultiSelecting)
{
RectangleGeometry geometry = new RectangleGeometry(
new Rect(selectionSquareTopLeft, e.GetPosition(drawingSurface)));
List<DrawingVisual> visualsInRegion =
drawingSurface.GetVisuals(geometry);
MessageBox.Show(String.Format("You selected {0} square(s).", visualsInRegion.Count));
isMultiSelecting = false;
drawingSurface.DeleteVisual(selectionSquare);
drawingSurface.ReleaseMouseCapture();
}
}
}
}
效果图