以前在用WinForm的時候,可以通過GDI+接口在窗體上動態繪制自定義的圖形。在WPF中有沒有對應的API呢,最近項目中用到了這個,在這里總結一下。
WPF中的Drawing主要提供了幾類API:
1. Drawing類型
該組類型主要用來對繪制的對象的描述。比如GeometryDrawing是描述一個幾何圖形的Drawing,它的Geometry屬性定義了它所描述的幾何圖形是什么樣子。(它可以是如下Geometry類型的派生類型的任何一種,GeometryGroup是對多個Geometry的組合)
與GeometryGroup一樣,DrawingGroup是對多個Drawing的組合。
2. DrawingContext類型
Drawing類型是以對象的形式來描述要繪制的圖形,文字或視頻。DrawingContext是通過存儲繪制命令的形式來對要繪制的對象進行描述。這種方式更加簡單。我們可以通過DrawingGroup.Open方法來得到一個DrawingContext,然后可以調用如下接口來進行操作。
探其究竟,其實DrawingContext僅僅是將對Drawing對象的創建與管理進行了包裝,然后提供了一組比較方便使用的接口而已。
看反編譯出來的代碼:
public override void DrawEllipse(Brush brush, Pen pen, Point center, AnimationClock centerAnimations, double radiusX, AnimationClock radiusXAnimations, double radiusY, AnimationClock radiusYAnimations) { this.VerifyApiNonstructuralChange(); if ((brush != null) || (pen != null)) { EllipseGeometry newFreezable = new EllipseGeometry(center, radiusX, radiusY) { CanBeInheritanceContext = this.CanBeInheritanceContext }; this.SetupNewFreezable(newFreezable, ((centerAnimations == null) && (radiusXAnimations == null)) && (radiusYAnimations == null)); if (centerAnimations != null) { newFreezable.ApplyAnimationClock(EllipseGeometry.CenterProperty, centerAnimations); } if (radiusXAnimations != null) { newFreezable.ApplyAnimationClock(EllipseGeometry.RadiusXProperty, radiusXAnimations); } if (radiusYAnimations != null) { newFreezable.ApplyAnimationClock(EllipseGeometry.RadiusYProperty, radiusYAnimations); } this.AddNewGeometryDrawing(brush, pen, newFreezable); } } private void AddNewGeometryDrawing(Brush brush, Pen pen, Geometry geometry) { GeometryDrawing newFreezable = new GeometryDrawing { CanBeInheritanceContext = this.CanBeInheritanceContext, Brush = brush, Pen = pen, Geometry = geometry }; this.SetupNewFreezable(newFreezable, (((brush == null) || brush.IsFrozen) && ((pen == null) || pen.IsFrozen)) && geometry.IsFrozen); this.AddDrawing(newFreezable); } private void AddDrawing(Drawing newDrawing) { if (this._rootDrawing == null) { this._rootDrawing = newDrawing; } else if (this._currentDrawingGroup == null) { this._currentDrawingGroup = new DrawingGroup(); this._currentDrawingGroup.CanBeInheritanceContext = this.CanBeInheritanceContext; this.SetupNewFreezable(this._currentDrawingGroup, false); this._currentDrawingGroup.Children.Add(this._rootDrawing); this._currentDrawingGroup.Children.Add(newDrawing); this._rootDrawing = this._currentDrawingGroup; } else { this._currentDrawingGroup.Children.Add(newDrawing); } }
3.接受Drawing作為Content的類型
可以通過這些類型來應用Drawing中描述的對象繪制。
主要有如下幾種:
(1)DrawingImage,結合Image控件可以將Drawing顯示在UI上
(2) DrawingBrush, 都有了Brush了,那就可以在仍何控件畫了。比如說作為控件的Background.
(3) DrawingVisual類型
通過該類型,可以將Drawing創建為一個Visual.然后可以將Visual提供給一VisualContainer(可以自定義從FrameworkElement派生的類型,然后重寫GetVisualChild與VisualChildrenCount方法作為VisualContainer)作為其UI呈現。
結合RenderTargetBitmap和BitmapEncoder, 我們可以將Drawing呈現到Bitmap圖片文件中。