• Drawing


     Drawing 对象不支持布局、输入和焦点,因此它们提供性能优势,使其非常适合用于描述背景、剪贴画以及用于对象的低级别绘图 Visual 。

    由于 Drawing对象是一个类型 Freezable 对象,因此 Drawing 对象获取几个特殊功能,其中包括:它们可以声明为资源、在多个对象之间共享、变为只读以提高性能、克隆以及使线程安全。

    <Page 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="PresentationOptions"
      Background="White" Margin="20">
    
      <Border BorderBrush="Gray" BorderThickness="1" 
        HorizontalAlignment="Left" VerticalAlignment="Top"
        Margin="10">
    
        <!-- This image uses a Drawing object for its source. -->
        <Image>
          <Image.Source>
            <DrawingImage PresentationOptions:Freeze="True">
              <DrawingImage.Drawing>
                <GeometryDrawing>
                  <GeometryDrawing.Geometry>
                    <GeometryGroup>
                      <EllipseGeometry Center="50,50" RadiusX="45" RadiusY="20" />
                      <EllipseGeometry Center="50,50" RadiusX="20" RadiusY="45" />
                    </GeometryGroup>
                  </GeometryDrawing.Geometry>
                  <GeometryDrawing.Brush>
                    <LinearGradientBrush>
                      <GradientStop Offset="0.0" Color="Blue" />
                      <GradientStop Offset="1.0" Color="#CCCCFF" />
                    </LinearGradientBrush>
                  </GeometryDrawing.Brush>
                  <GeometryDrawing.Pen>
                    <Pen Thickness="10" Brush="Black" />
                  </GeometryDrawing.Pen>
                </GeometryDrawing>
              </DrawingImage.Drawing>
            </DrawingImage>
          </Image.Source>
        </Image>
      </Border>
    
    </Page>

    为了使用DrawingVisual对象,您需要为对象创建一个宿主容器。 主机容器对象必须派生自FrameworkElement类,该类提供类缺少的DrawingVisual布局和事件处理支持。 宿主容器对象不显示任何可视属性,因为它的主要用途是包含子对象。

    为可视对象创建宿主容器对象时,需要在 中VisualCollection存储可视对象引用。

    // Create a host visual derived from the FrameworkElement class.
    // This class provides layout, event handling, and container support for
    // the child visual objects.
    public class MyVisualHost : FrameworkElement
    {
        // Create a collection of child visual objects.
        private VisualCollection _children;
    
        public MyVisualHost()
        {
            _children = new VisualCollection(this);
            _children.Add(CreateDrawingVisualRectangle());
            _children.Add(CreateDrawingVisualText());
            _children.Add(CreateDrawingVisualEllipses());
    
            // Add the event handler for MouseLeftButtonUp.
            this.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(MyVisualHost_MouseLeftButtonUp);
        }

    宿主容器对象负责管理其视觉对象的集合。 这要求主机容器实现成员重写派生FrameworkElement类。

    下表介绍了必须重写的两个成员:

    在下面的示例中,将实现两FrameworkElement个成员的重写。

    // Provide a required override for the VisualChildrenCount property.
    protected override int VisualChildrenCount
    {
        get { return _children.Count; }
    }
    
    // Provide a required override for the GetVisualChild method.
    protected override Visual GetVisualChild(int index)
    {
        if (index < 0 || index >= _children.Count)
        {
            throw new ArgumentOutOfRangeException();
        }
    
        return _children[index];
    }

    事件处理例程可以通过调用HitTest方法实现命中测试。

    // Capture the mouse event and hit test the coordinate point value against
    // the child visual objects.
    void MyVisualHost_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        // Retrieve the coordinates of the mouse button event.
        System.Windows.Point pt = e.GetPosition((UIElement)sender);
    
        // Initiate the hit test by setting up a hit test result callback method.
        VisualTreeHelper.HitTest(this, null, new HitTestResultCallback(myCallback), new PointHitTestParameters(pt));
    }
    
    // If a child visual object is hit, toggle its opacity to visually indicate a hit.
    public HitTestResultBehavior myCallback(HitTestResult result)
    {
        if (result.VisualHit.GetType() == typeof(DrawingVisual))
        {
            if (((DrawingVisual)result.VisualHit).Opacity == 1.0)
            {
                ((DrawingVisual)result.VisualHit).Opacity = 0.4;
            }
            else
            {
                ((DrawingVisual)result.VisualHit).Opacity = 1.0;
            }
        }
    
        // Stop the hit test enumeration of objects in the visual tree.
        return HitTestResultBehavior.Stop;
    }

    创建DrawingVisual 对象

    // Create a DrawingVisual that contains a rectangle.
    private DrawingVisual CreateDrawingVisualRectangle()
    {
        DrawingVisual drawingVisual = new DrawingVisual();
    
        // Retrieve the DrawingContext in order to create new drawing content.
        DrawingContext drawingContext = drawingVisual.RenderOpen();
    
        // Create a rectangle and draw it in the DrawingContext.
        Rect rect = new Rect(new System.Windows.Point(160, 100), new System.Windows.Size(320, 80));
        drawingContext.DrawRectangle(System.Windows.Media.Brushes.LightBlue, (System.Windows.Media.Pen)null, rect);
    
        // Persist the drawing content.
        drawingContext.Close();
    
        return drawingVisual;
    }

    将 Visual 编码为图像文件

    // Base Image
    BitmapImage bi = new BitmapImage();
    bi.BeginInit();
    bi.UriSource = new Uri("sampleImages/waterlilies.jpg",UriKind.Relative);
    bi.DecodePixelWidth = 200;
    bi.EndInit();
    
    // Text to render on the image.
    FormattedText text = new FormattedText("Waterlilies",
            new CultureInfo("en-us"),
            FlowDirection.LeftToRight,
            new Typeface(this.FontFamily, FontStyles.Normal, FontWeights.Normal, new FontStretch()),
            this.FontSize,
            Brushes.White);
    
    // The Visual to use as the source of the RenderTargetBitmap.
    DrawingVisual drawingVisual = new DrawingVisual();
    DrawingContext drawingContext = drawingVisual.RenderOpen();
    drawingContext.DrawImage(bi,new Rect(0,0,bi.Width,bi.Height));
    drawingContext.DrawText(text, new Point(bi.Height/2, 0));
    drawingContext.Close();
    
    // The BitmapSource that is rendered with a Visual.
    RenderTargetBitmap rtb = new RenderTargetBitmap(bi.PixelWidth, bi.PixelHeight, 96, 96, PixelFormats.Pbgra32);
    rtb.Render(drawingVisual);
    
    // Encoding the RenderBitmapTarget as a PNG file.
    PngBitmapEncoder png = new PngBitmapEncoder();
    png.Frames.Add(BitmapFrame.Create(rtb));
    using (Stream stm = File.Create("new.png"))
    {
       png.Save(stm);
    }

    复合几何图形

    使用 GeometryGroupCombinedGeometry 或者通过调用静态的 Geometry 方法 Combine,可以创建复合几何图形对象。它们主要的区别是:

    • CombinedGeometry 对子图形进行叠加操作,没有面积的子图形将被丢弃。只能组合两个子图形(但是这两个子图形也可以是复合几何图形)。CombinedGeometry的叠加方式有四种:UnionIntersectExclude 和 Xor
    • GeometryGroup 只进行组合,而不进行面积叠加。可以添加多个子图形。填充方式由FillRule设定

    Geometry对象中本身还包含了一系列非常有用的方法,如:

    FillContains,StrokeContains用于鼠标命中测试是非常方便的。

    Geometry对象并不能作为图像独立呈现出来,它一般有如下几种呈现方式:

    • 在Path中呈现
    • 在DrawingContext中呈现
    • 在GeometryDrawing中呈现

    DrawingContext比较类似WinForm中的Graphics 类,是基础的绘图对象,用于绘制各种图形。使用DrawingContext绘图的一个最简单的方式是重载控件的OnRender方法

  • 相关阅读:
    ASP.NET MVC学习笔记-----ActionInvoker
    quartz启动报错
    THUSC 2021 游记
    C++下随机数的生成
    友链
    memset一些技巧
    CodeForces Round #705 总结&题解
    php计算两坐标距离
    vue中使用keepAlive组件缓存遇到的坑
    vue 中 keepAlive
  • 原文地址:https://www.cnblogs.com/yetsen/p/13579653.html
Copyright © 2020-2023  润新知