• WPF中自定义绘制内容


    先说结论:实现了在自定义大小的窗口中,加载图片,并在图片上绘制一个矩形框;且在窗口大小改变的情况,保持绘制的矩形框与图片的先对位置不变。

    在WinForm中,我们可以很方便地绘制自己需要的内容,在WPF中似乎被限制了,不能够很方便的使用;然后需求有总是奇葩的,所以在这里简单地总结一下。

    在WinForm中,如果需要自己绘制,就需要拿到Graphics对象;同样的,我们就希望在WPF也得到一个其同样作用的对象,这个对象就是DrawingContext类的实例对象。

    具体来说,就是要重载 UIElement 类的 OnRender 方法。

     1 public class YourControl : UIElement
     2 {
     3     /// <summary>
     4     /// 重写绘制
     5     /// </summary>
     6     protected override void OnRender(DrawingContext drawingContext)
     7     {
     8         // your logic here
     9     }
    10 }

    Talk is cheap, here is the code. 下面的代码完整的组织后,编译可运行,已经调试通了;希望对看到的同学有帮助,有问题,我们也可以探讨。

    • 项目的组织方式;

    • DrawableGrid.cs
      1 using System;
      2 using System.Windows;
      3 using System.Windows.Controls;
      4 using System.Windows.Input;
      5 using System.Windows.Media;
      6 using System.Windows.Media.Imaging;
      7 
      8 namespace draw
      9 {
     10     /// <summary>
     11     /// 基本思想
     12     /// 1 在绘制结束时,计算相对于图片真实大小的情况下,绘制的矩形框的大小,及相对于图片的偏移
     13     /// 2 每次刷新绘制前,计算当前窗口大小,及应该绘制的图片的大小,及其偏移
     14     /// 3 每次刷新绘制前,计算绘制的矩形框,相对于当前图片的偏移
     15     /// 其中,
     16     /// 框的偏移及大小,每次使用针对原始图片的数据,作为基础来计算比例,就能够保证即使窗体缩小到0,依旧可以恢复
     17     /// </summary>
     18     public class DrawableGrid : Control
     19     {
     20         #region vars
     21 
     22         private Point mousedown;
     23         private Point mouseup;
     24         private bool mouseBtnDown = false;
     25         private bool bSelectionDraw = false;
     26 
     27         private SolidColorBrush mBrush = Brushes.LightBlue;
     28         private Pen mPen = new Pen(Brushes.Red, 1);
     29         private BitmapImage Img = null;
     30 
     31         private Grid drawgrid;
     32 
     33         private Rect curPicRect;
     34         private Rect curSelectRect;
     35 
     36         private Rect realSelectRect;
     37         private Rect realPicRect;
     38 
     39         #endregion
     40 
     41         #region ctors
     42 
     43         static DrawableGrid()
     44         {
     45             DefaultStyleKeyProperty.OverrideMetadata(typeof(DrawableGrid), new FrameworkPropertyMetadata(typeof(DrawableGrid)));
     46         }
     47 
     48         #endregion
     49 
     50         #region overrides
     51 
     52         /// <summary>
     53         /// 重写绘制
     54         /// </summary>
     55         protected override void OnRender(DrawingContext drawingContext)
     56         {
     57             if (Img == null)
     58                 return;
     59 
     60             curPicRect = CalcRect(Img.Height, Img.Width, this.ActualHeight, this.ActualWidth);
     61             curSelectRect = CalcResizeRect(curPicRect.X, curPicRect.Y, realSelectRect.X, realSelectRect.Y, realSelectRect.Height, realSelectRect.Width, curPicRect.Height / realPicRect.Height);
     62 
     63             drawingContext.DrawImage(Img, curPicRect);
     64 
     65             if (mouseBtnDown)
     66             {
     67                 int xmin = (int)Math.Min(mousedown.X, mouseup.X);
     68                 int xmax = (int)Math.Max(mousedown.X, mouseup.X);
     69                 int ymin = (int)Math.Min(mousedown.Y, mouseup.Y);
     70                 int ymax = (int)Math.Max(mousedown.Y, mouseup.Y);
     71                 var r = new Rect(xmin, ymin, xmax - xmin, ymax - ymin);
     72                 drawingContext.DrawRectangle(mBrush, mPen, r);
     73             }
     74 
     75             if (bSelectionDraw)
     76             {
     77                 drawingContext.DrawRectangle(mBrush, mPen, curSelectRect);
     78             }
     79 
     80             base.OnRender(drawingContext);
     81         }
     82 
     83         public override void OnApplyTemplate()
     84         {
     85             drawgrid = GetTemplateChild("drawgrid") as Grid;
     86             if (drawgrid != null)
     87             {
     88                 drawgrid.MouseDown += drawgrid_MouseDown;
     89                 drawgrid.MouseMove += drawgrid_MouseMove;
     90                 drawgrid.MouseUp += drawgrid_MouseUp;
     91             }
     92 
     93             string picaddr = System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "pic", "2.jpg");
     94             Img = new BitmapImage(new Uri(picaddr));
     95             realPicRect = new Rect(0, 0, Img.Width, Img.Height);
     96         }
     97 
     98         #endregion
     99 
    100         #region methods
    101 
    102         /// <summary>
    103         /// 计算图片大小相对于当前的控件大小,应该如何展示
    104         /// </summary>
    105         /// <param name="imgHeight">图片高</param>
    106         /// <param name="imgWidth">图片宽</param>
    107         /// <param name="gridHeight">容器高</param>
    108         /// <param name="gridWidth">容器宽</param>
    109         /// <returns>当前实际应该绘制图片的矩形大小及相对于容器的偏移</returns>
    110         private Rect CalcRect(double imgHeight, double imgWidth, double gridHeight, double gridWidth)
    111         {
    112             Rect rect;
    113             double imgRatio = imgHeight / imgWidth;
    114             double gridRatio = gridHeight / gridWidth;
    115 
    116             if (imgRatio >= gridRatio)
    117             {
    118                 double hi = gridHeight;
    119                 double wi = gridHeight / imgRatio;
    120 
    121                 double left = (gridWidth - wi) / 2;
    122                 double top = 0;
    123 
    124                 rect = new Rect(left, top, wi, hi);
    125             }
    126             else
    127             {
    128                 double wi = gridWidth;
    129                 double hi = gridWidth * imgRatio;
    130 
    131                 double left = 0;
    132                 double top = (gridHeight - hi) / 2;
    133 
    134                 rect = new Rect(left, top, wi, hi);
    135             }
    136 
    137             return rect;
    138         }
    139 
    140         /// <summary>
    141         /// 在图片上绘制的框相对于图片的位置
    142         /// </summary>
    143         private Rect CalcResizeRect(double curx, double cury, double lastx, double lasty, double lastheight, double lastwidth, double ratio)
    144         {
    145             double x = curx + lastx * ratio;
    146             double y = cury + lasty * ratio;
    147             double wid = lastwidth * ratio;
    148             double hei = lastheight * ratio;
    149             return new Rect(x, y, wid, hei);
    150         }
    151 
    152         #endregion
    153 
    154         #region events
    155 
    156         private void drawgrid_MouseDown(object sender, MouseButtonEventArgs e)
    157         {
    158             if (e.LeftButton == MouseButtonState.Pressed && e.RightButton == MouseButtonState.Released)
    159             {
    160                 bSelectionDraw = false;
    161                 mouseBtnDown = true;
    162                 mousedown = e.GetPosition(drawgrid);
    163             }
    164         }
    165 
    166         private void drawgrid_MouseMove(object sender, MouseEventArgs e)
    167         {
    168             if (mouseBtnDown)
    169             {
    170                 mouseup = e.GetPosition(drawgrid);
    171                 this.InvalidateVisual();
    172             }
    173         }
    174 
    175         private void drawgrid_MouseUp(object sender, MouseButtonEventArgs e)
    176         {
    177             if (e.LeftButton == MouseButtonState.Released && e.RightButton == MouseButtonState.Released)
    178             {
    179                 bSelectionDraw = true;
    180                 mouseBtnDown = false;
    181                 mouseup = e.GetPosition(drawgrid);
    182 
    183                 int xmin = (int)Math.Min(mousedown.X, mouseup.X);
    184                 int xmax = (int)Math.Max(mousedown.X, mouseup.X);
    185                 int ymin = (int)Math.Min(mousedown.Y, mouseup.Y);
    186                 int ymax = (int)Math.Max(mousedown.Y, mouseup.Y);
    187 
    188                 var relativeRect = new Rect(xmin, ymin, xmax - xmin, ymax - ymin);
    189                 var fullSizeImgRect = CalcRect(Img.Height, Img.Width, Img.Height, Img.Width);
    190                 double tempration = fullSizeImgRect.Height / curPicRect.Height;
    191                 realSelectRect = CalcResizeRect(fullSizeImgRect.X, fullSizeImgRect.Y, relativeRect.X - curPicRect.X, relativeRect.Y - curPicRect.Y, relativeRect.Height, relativeRect.Width, tempration);
    192             }
    193         }
    194 
    195         #endregion
    196     }
    197 }
    • DrawableGrid.xaml
     1 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     2                     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     3                     xmlns:local="clr-namespace:draw">
     4     
     5     <Style TargetType="{x:Type local:DrawableGrid}">
     6         <Setter Property="Template">
     7             <Setter.Value>
     8                 <ControlTemplate TargetType="{x:Type local:DrawableGrid}">
     9                     <Grid x:Name="drawgrid" Background="Transparent" />
    10                 </ControlTemplate>
    11             </Setter.Value>
    12         </Setter>
    13     </Style>
    14 </ResourceDictionary>
    • Generic.xaml
    1 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    2                     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    3 
    4     <ResourceDictionary.MergedDictionaries>
    5         <ResourceDictionary Source="draw;component/DrawableGrid/DrawableGrid.xaml" />
    6     </ResourceDictionary.MergedDictionaries>
    7 
    8 </ResourceDictionary>
    • MainWindow.xaml
    1 <Window x:Class="draw.MainWindow"
    2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4         xmlns:local="clr-namespace:draw"
    5         Title="MainWindow" Height="500" Width="500">
    6     <local:DrawableGrid />
    7 </Window>
    • MainWindow.xaml.cs
     1 using System.Windows;
     2 
     3 namespace draw
     4 {
     5     public partial class MainWindow : Window
     6     {
     7         public MainWindow()
     8         {
     9             InitializeComponent();
    10         }
    11     }
    12 }
  • 相关阅读:
    OpenCV 2.4.11 VS2012 Configuration
    [LeetCode] 11. Container With Most Water 装最多水的容器
    Android rxjava2的disposable
    Android在应用设置里关闭权限,返回生命周期处理
    Android 使用greenDAO 3.2.2 操作外部数据库
    Android中intent相关,setFlag(xx);
    Android 关于Acitivity 的setFlag以及launchmode的总结
    GreenDao3.0新特性解析(配置、注解、加密)
    Android RecycleView实现混合Item布局
    Android各大手机系统打开权限管理页面
  • 原文地址:https://www.cnblogs.com/warnet/p/5491603.html
Copyright © 2020-2023  润新知