热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

详解WPF的InkCanvas选择模式

这篇文章主要介绍了WPFInkCanvas选择模式的相关资料,帮助大家更好的理解和学习使用c#wpf,感兴趣的朋友可以了解下

InkCanvas是WPF中进行墨迹绘制的控件,本文介绍下InkCanvas控件是如何进行选择操作的。文中有误的地方希望大家进行批评指正。

InkCanvas的选择效果

使用WPF可以轻松实现白板功能,只需要添加一个InkCanvas控件。修改InkCanvas的EditingMode属性可以控制InkCanvas的操作模式,如书写、选择、擦除等模式。
如下demo在窗口中添加一个InkCanvas,然后添加一个Button实现书写与选择模式的切换。

// xaml

  
  

运行demo,书写后点击按钮进行选择,可以看到InkCanvas的选择操作如下图所示:

从图中可以看出,InkCanvas的选择效果有如下特点:

  1. 选中后笔迹高亮;
  2. 选中后显示选择框;
  3. 拖动选择框,选择框随着鼠标移动,但选择的笔迹并未移动。

接下来看下WPF是如何实现这种选择操作的。

InkCanvas选择模式的实现

首先,InkCanvas的编辑功能(书写、擦除、选择等)是通过EditingCoordinator管理的,该类包含一系列的EditingBehavior,实现选择过程的为LassoSelectionBehavior类,实现选择后对选择框操作的为SelectionEditor与SelectionEditingBehavior。本文主要介绍选择后对选择框的操作过程,选择过程以及笔迹的高亮显示打算单独写一篇文章进行介绍。

在InkCanvas中,与选择功能相关的对象有InkCanvasSelection、InkCanvasSelectionAdorner及InkCanvasFeedbackAdorner。后两者为装饰器,装饰器的介绍可参考官方文档。

先看InkCanvasSelectionAdorner类,直接看其OnRender方法,代码如下。首先绘制了选择框的背景,然后绘制了选择框(矩形虚线效果),最后绘制了选择框上的9个小矩形按钮。按钮可以进行拖动调节,具体实现逻辑可以看代码,本文不赘述。

protected override void OnRender(DrawingContext drawingContext)
{
  DrawBackground(drawingContext);

  Rect rectWireFrame = GetWireFrameRect()
  if(!rectWireFrame.IsEmpty)
  {
    drawingContext.DrawRectangle(null, _adornerBorderPen, rectWireFrame);

    DrawHandles(drawingContext, rectWireFrame);
  }
}

再看InkCanvasFeedbackAdorner类,同样看OnRender方法,代码如下。其仅绘制了矩形虚线选择框,通过这两个类的OnRender方法,结合上文中的动画,可以知道选中后使用InkCanvasSelectionAdorner进行装饰,对选择框的操作(拖动)使用InkCanvasFeedbackAdorner进行装饰。

protected override void OnRender(DrawingContext drawingContext)
{
  drawingContext.DrawRectangle(null, _adornerBorderPen,
    new Rect(CornerResizeHandleSize / 2, CornerResizeHandleSize / 2,
    _frameSize.Width - CornerResizeHandleSize, _frameSize.Height - CornerResizeHandleSize));
}

接下来看下这两个Adorner是对谁进行装饰的,首先看InkCanvas的OnPreApplyTemplate方法,代码如下。注释部分是InkCanvas的Visual Tree,可以了解到InkCanvas的内部结构。再看下SelectionAdorner的初始化,可以看出是对InnerCanvas进行装饰,InnerCanvas是InkCanvas的内部容器,放置笔迹及其它UIElement。SelectionAdorner添加了对ActiveEditingMode的绑定,当Mode为None时,隐藏,否则显示。FeedbackAdorner的装饰对象通过其构造函数可以看出,也是装饰的InnerCanvas。

internal override void OnPreApplyTemplate()
{
  base.OnPreApplyTemplate();

  // Build our visual tree here.
  // 
  //   
  //     
  //       
  //       
  //       
  //     
  //     
  //       
  //       
  //     
  //   
  // 

  if(_localAdornerDecorator == null)
  {
    _localAdornerDecorator = new AdornerDecorator();
    InkPresenter inkPresenter = InkPresenter;

    AddVisualChild(_localAdornerDecorator);
    _localAdornerDecorator.Child = inkPresenter;
    inkPresenter.Child = InnerCanvas;

    _localAdornerDecorator.AdornerLayer.Add(SelectionAdorner);
  }
}

internal InkCanvasSelectionAdorner SelectionAdorner
{
  get
  {
    if(_selectiOnAdorner== null)
    {
      _selectiOnAdorner= new InkCanvasSelectionAdorner(InnerCanvas);

      Binding activedEditingModeBinding = new Binding();
      activedEditingModeBinding.Path = new PropertyPath(InkCanvas.ActiveEditingModeProperty);
      activedEditingModeBinding.Mode = BindingMode.OneWay;
      activedEditingModeBinding.Source = this;
      activedEditingModeBinding.COnverter= new ActiveEditingMode2VisibilityConverter();
      _selectionAdorner.SetBinding(UIElement.VisibilityProperty, activedEditingModeBinding);
    }

    return _selectionAdorner;
  }
}

// InkCanvasFeedbackAdorner
internal InkCanvasFeedbackAdorner(InkCanvas inkCanvas)
  : base((inkCanvas != null ? inkCanvas.InnerCanvas : null))
  {...}

最后,我们看下对选择框进行的操作是如何实现的。选择后会激活SelectionEditingBehavior,在其OnActivate方法中,绑定了SelectionAdorner的MouseMove/MouseUp/LostMouseCapture事件,并调用InkCanvasSelection.StartFeedbackAdorner()方法对FeedbackAdorner进行初始化,将其添加到AdornerLayer中。然后通过响应MouseMove,调用InkSelection.UpdateFeedbackAdorner()方法更新FeedbackAdorner的位置。最后在MouseUp响应中释放FeedbackAdorner。删减代码如下,具体的实现逻辑可以看WPF源码。

protected override void OnActive()
{
  // ...
  InkCanvas.InkCanvasSelection.StartFeedbackAdorner(_selectionRect, _hitResult);

  InkCanvas.SelectionAdorner.AddHandler(Mouse.MouseUpEvent, new MouseButtonEventHandler(OnMouseUp));
  InkCanvas.SelectionAdorner.AddHandler(Mouse.MouseMoveEvent, new MouseEventHandler(OnMouseMove));
  InkCanvas.SelectionAdorner.AddHandler(Mouse.LostMouseCaptureEvent, new MouseEventHandler(OnLostMouseCapture));
}

private void OnMouseMove(object sender, MouseEventArgs args)
{
  // ...
  InkCanvas.InkCanvasSelection.UpdateFeedbackAdorner(newRect);
  // ...
}

以上就是详解WPF的InkCanvas选择模式的详细内容,更多关于WPF的InkCanvas选择模式的资料请关注其它相关文章!


推荐阅读
  • 本文详细介绍了Flutter中的Stack、IndexedStack以及Positioned三个布局组件的使用方法和应用场景。Stack允许开发者以堆叠的方式展示多个子组件;IndexedStack则提供了一种仅显示指定索引子组件的方法;而Positioned则是Stack的子组件,用于精确定位子组件的位置。 ... [详细]
  • 在进行微信小程序开发过程中,遇到了需要实现类似微信朋友圈那样的长文本折叠功能的需求。本文将详细探讨其实现方法及注意事项。 ... [详细]
  • SaaS定价策略:数学建模与商业交易重构
    本文探讨了如何通过数学建模来优化SaaS产品的定价策略,并详细介绍了将传统应用转化为云应用时,所需进行的业务功能和架构层面的调整。 ... [详细]
  • 探讨在特定情况下使用 Knockout.js 的 if 或 visible 绑定的最佳实践,特别是在处理未定义对象时的策略。 ... [详细]
  • 深入解析:主流开源分布式文件系统综述
    本文详细探讨了几款主流的开源分布式文件系统,包括HDFS、MooseFS、Lustre、GlusterFS和CephFS,重点分析了它们的元数据管理和数据一致性机制,旨在为读者提供深入的技术见解。 ... [详细]
  • Spring框架中@Autowired注解对接口与其实现类的绑定机制解析
    本文深入探讨了Spring框架中@Autowired注解的工作原理,特别是当其应用于接口而非实现类时的情况,以及如何处理接口拥有多个实现类的情形。旨在为开发者提供有效的指导。 ... [详细]
  • 持续集成概述与实践指南
    本文探讨了持续集成(CI)的基本概念、目的及其在现代软件开发中的应用。通过实例分析,帮助读者理解如何有效实施持续集成,提高软件开发效率。 ... [详细]
  • 纵向|发生_ListView和EditText使用解决方案 ... [详细]
  • StackEngine,一家位于德克萨斯州奥斯汀的新兴科技公司,近期发布了一套全新的工具集,旨在首次实现Docker生产环境应用的统一管理和自动化。此外,该公司还透露已从多家知名风险投资机构获得了初步的资金支持。 ... [详细]
  • 利用HTML5 Canvas高效构建电信网络拓扑图
    电信网络拓扑图在实际应用中具有很高的实用价值。本文介绍了一个基于HTML5 Canvas的电信网络拓扑图项目,不仅实现了基本的图形展示功能,还加入了自动布局和属性栏功能,使项目更加完善。此Demo经过细微调整即可直接应用于实际项目中。 ... [详细]
  • 深入解析CSS中的BFC(块级格式化上下文)
    本文详细介绍了CSS中的块级格式化上下文(Block Formatting Context, BFC)的概念、形成条件及其在网页布局中的应用。通过实例讲解如何利用BFC解决常见的布局问题。 ... [详细]
  • 随着Spring框架的不断发展,其灵活性和可选性成为其显著特点。Java EE虽然专注于少数核心技术,但这种专注限制了更多创新解决方案的发展。Spring框架的出现打破了这一局面,不仅简化了Java EE,还通过持续的技术革新,为开发者提供了更多的选择和支持。 ... [详细]
  • SVG画布HTML5提供两种强有力的“画布”:SVG和Canvas。SVG的特点:SVG绘制的是矢量图,因此对图像进行放大不会失真基于XM ... [详细]
  • Docker基础指南:快速入门与实践
    Docker自发布以来便受到广泛欢迎,其提供的容器化技术极大地简化了软件开发和部署流程。本文旨在帮助初学者快速掌握Docker的基本操作,包括安装、运行容器、创建和管理镜像等内容,以激发大家对Docker的兴趣。 ... [详细]
  • 本文详细介绍了 Spring Boot 的启动过程,包括初始化、资源加载、上下文创建及配置加载等关键步骤,帮助开发者深入理解 Spring Boot 的内部机制。 ... [详细]
author-avatar
Missluckyyy_879
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有