WPF 使用InkCanvas实现画板的缩放以及移动

最近博主需要实现一个画板功能,可以写字并且支持触屏的手势缩放以及拖动。

找资料的时候发现网上相关资料特别少,于是经历了#$#@!##$#¥#$*就完成了。

上教程:

1.首先我们要实现一个最基本的画板功能,只需要简单的一行代码即可:

对InkCanvas如还有不会使用的,参考这篇文章(WPF InkCanvas 画图 基础使用教程

  <InkCanvas Width="1000" Height="1000" />

这样我们便有了一个最基本的画板,下面我们先用鼠标滚轮来实现画板放大缩小。

   <Grid  Background="Blue"   x:Name="touchGrid">
            <InkCanvas  Background="AntiqueWhite" 
                    x:Name="ink" 
                    MouseWheel="ink_MouseWheel" />
        </Grid>
2.鼠标滚轮实现缩放以及移动

如果对InkCanvas本身控件进行缩放移动,那么将会露出部分父容器Grid的背景色,要解决这个问题,我们只需要对墨迹进行缩放即可,对ink.Strokes进行操作,使用Transform方法对其进行变换,Matrix是一个矩阵变换的类(C# 矩阵变换Matrix),然而我们用自带的方法就OK了,以鼠标为中心点进行缩放:

   private void ink_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            if (e.Delta < 0)
            {
                foreach (Stroke stroke in ink.Strokes)
                {
                    Matrix matrix = new Matrix();
                    //缩小     小于1为缩小(最好不要为负数),大于1为放大,此为缩小0.8倍
                    matrix.ScaleAt(0.8, 0.8, Mouse.GetPosition(ink).X, Mouse.GetPosition(ink).Y);
                    //X轴移动  正数为右,负数为左,此为右移1.2倍   斜着移动设置两个值
                    matrix.Translate(1.2, 0);
                    stroke.Transform(matrix, false);
                }
            }
            else
            {
                foreach (Stroke stroke in ink.Strokes)
                {
                    Matrix matrix = new Matrix();
                    //放大     此为放大1.25倍
                    matrix.ScaleAt(1.25, 1.25, Mouse.GetPosition(ink).X, Mouse.GetPosition(ink).Y);
                    //Y轴移动 此为左移1.2倍
                    matrix.Translate(0, 1.2);
                    stroke.Transform(matrix, false);
                }
            }
        }
3.触屏实现

我们需要了解几个事件并通过他们完成各种手势操作:ManipulationStarting(开始)、ManipulationStarted(开始以后)、ManipulationDelta(手势)、ManipulationInertiaStarting(惯性)、ManipulationCompleted(完成),并把控件的IsManipulationEnabled设为"True",于是就出现了下面的代码:

  <Grid   x:Name="touchGrid"
                ManipulationStarting="touchGrid_ManipulationStarting"  
                ManipulationDelta="touchGrid_ManipulationDelta"
                ManipulationCompleted="touchGride_ManipulationCompleted">
        <InkCanvas  Background="AntiqueWhite"    x:Name="ink"  IsManipulationEnabled="True"  
                    MouseWheel="ink_MouseWheel"
                    PreviewTouchDown="ink_PreviewTouchDown"  
                    PreviewTouchUp="ink_PreviewTouchUp" />
    </Grid>

经博主实验,我们面临了几个比较坑的问题:

1.WPF识别多个鼠标或者触摸设备是异步的

2.InkCanvas触摸/点击移动就会留下墨迹

3.手势如何实现

为了解决第一个问题,我们使用PreviewTouchDown事件进行设备的捕获并保存,第二个问题我们只需要让画笔的InkCanvasEditingMode属性为None:

定义全局变量

 
 //记录触摸设备ID
  private List<int> dec = new List<int>();
 //中心点
  Point centerPoint;

PreviewTouchDown事件:

 private void ink_PreviewTouchDown(object sender, TouchEventArgs e)
        {
            dec.Add(e.TouchDevice.Id);
            //设备1个的时候,记录中心点
            if (dec.Count == 1)
            {
                TouchPoint touchPoint = e.GetTouchPoint(ink);
                centerPoint = touchPoint.Position;
            }
            //设备两个及两个以上,将画笔功能关闭
            if (dec.Count > 1)
            {
                if (ink.EditingMode != InkCanvasEditingMode.None)
                {
                    ink.EditingMode = InkCanvasEditingMode.None;
                }
            }
        }
PreviewTouchUp事件:
 private void ink_PreviewTouchUp_PreviewTouchUp(object sender, TouchEventArgs e)
        {
            //手势完成后切回之前的状态
            if (dec.Count > 1)
            {
                if (ink.EditingMode == InkCanvasEditingMode.None)
                {
                    ink.EditingMode = InkCanvasEditingMode.Ink;
                }
            }
            dec.Remove(e.TouchDevice.Id);
        }

接下来我们需要实现手势的操作:

   private void touchGrid_ManipulationStarting(object sender, ManipulationStartingEventArgs e)
        {
            e.ManipulationContainer = ink;
            e.Mode = ManipulationModes.All;
        }
        private void touchGrid_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
        {
            //小于两指 不触发事件
            if (dec.Count < 2) return;
            //两指缩放
            if (dec.Count == 2)
            {
                foreach (Stroke stroke in ink.Strokes)
                {
                    Matrix matrix = new Matrix();
                    matrix.ScaleAt(e.DeltaManipulation.Scale.X, e.DeltaManipulation.Scale.Y, centerPoint.X, centerPoint.Y);
                    stroke.Transform(matrix, false);
                }
            }
            //三指滑动
            if (dec.Count == 3)
            {
                foreach (Stroke stroke in ink.Strokes)
                {
                    Matrix matrix = new Matrix();
                    matrix.Translate(e.DeltaManipulation.Translation.X, e.DeltaManipulation.Translation.Y);
                    stroke.Transform(matrix, false);
                }
            }
        }
        private void touchGride_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
        {
            //TODO 完成之后需要做的事情
        }

到此,基本的使用InkCanvas实现画板的缩放以及移动已经完成,需要Demo的可以点这个 链接


  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WPF(Windows Presentation Foundation)是一种用于创建Windows应用程序的框架,其中之一的功能是提供了InkCanvas控件,用于支持绘制和手写输入。 要保存InkCanvas上的部分画板,可以按照以下步骤进行: 1. 首先,确定需要保存的画板区域。可以使用C#代码获取InkCanvas上的绘制输入并将其转换为Bitmap或图像对象。 ``` // 获取InkCanvas上的绘制输入 StrokeCollection strokes = inkCanvas.Strokes; // 创建一个Rect对象表示需要保存的画板区域 Rect saveArea = new Rect(100, 100, 200, 200); // 示例:从(100, 100)坐标开始,宽高为200的矩形区域 ``` 2. 接下来,将指定区域的绘制内容提取出来,并将其保存为图像文件。 ``` // 根据保存区域创建一个副本画板 InkCanvas saveCanvas = new InkCanvas(); saveCanvas.Width = saveArea.Width; saveCanvas.Height = saveArea.Height; // 将原始InkCanvas上的指定绘制内容复制到副本画板 foreach (Stroke stroke in strokes) { if (stroke.GetBounds().IntersectsWith(saveArea)) { saveCanvas.Strokes.Add(stroke.Clone()); } } // 创建一个RenderTargetBitmap对象 RenderTargetBitmap renderBitmap = new RenderTargetBitmap((int)saveCanvas.Width, (int)saveCanvas.Height, 96d, 96d, PixelFormats.Default); // 将副本画板渲染到RenderTargetBitmap上 renderBitmap.Render(saveCanvas); // 创建一个PngBitmapEncoder对象,并将RenderTargetBitmap添加到编码器中 PngBitmapEncoder encoder = new PngBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(renderBitmap)); // 保存图像文件 using (FileStream stream = new FileStream("savedImage.png", FileMode.Create)) { encoder.Save(stream); } ``` 以上代码的关键是通过创建一个副本画板并将原始画板上的指定绘制内容复制到副本画板中,然后将副本画板渲染为RenderTargetBitmap,并使用PngBitmapEncoder保存为图像文件。 通过以上步骤,您可以将InkCanvas上的部分画板保存为图像文件,以便稍后进行显示或其他操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值