Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Framework / System / Windows / Shapes / Shape.cs / 1 / Shape.cs
//----------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Description: Shape element is a base class for shapes like Path,
// Rectangle, GlyphRun etc.
//
// History:
//
// 06/02/2003 : mleonov - created.
// 07/29/2004 : timothyc - Added ValidateValueCallback for enumeration
// properties
//
//---------------------------------------------------------------------------
using System.Diagnostics;
using System.Windows.Threading;
using System.Windows;
using System.Windows.Media;
using System.ComponentModel;
using MS.Internal;
using MS.Internal.PresentationFramework;
using System;
namespace System.Windows.Shapes
{
///
/// Shape is a base class for shape elements
///
[Localizability(LocalizationCategory.None, Readability=Readability.Unreadable)]
public abstract class Shape : FrameworkElement
{
#region Constructors
///
/// Shape Constructor
///
protected Shape()
{
}
#endregion
#region Properties
///
/// DependencyProperty for the Stretch property.
///
public static readonly DependencyProperty StretchProperty
= DependencyProperty.Register(
"Stretch", // Property name
typeof(Stretch), // Property type
typeof(Shape), // Property owner
new FrameworkPropertyMetadata(Stretch.None, FrameworkPropertyMetadataOptions.AffectsArrange));
///
/// The Stretch property determines how the shape may be stretched to accommodate shape size
///
public Stretch Stretch
{
get { return (Stretch)GetValue(StretchProperty); }
set { SetValue(StretchProperty, value); }
}
///
/// The RenderedGeometry property returns the final rendered geometry
///
public virtual Geometry RenderedGeometry
{
get
{
EnsureRenderedGeometry();
Geometry geometry = _renderedGeometry.CloneCurrentValue();
if (geometry == null || geometry == Geometry.Empty)
{
return Geometry.Empty;
}
// We need to return a frozen copy
if (Object.ReferenceEquals(geometry, _renderedGeometry))
{
// geometry is a reference to _renderedGeometry, so we need to copy
geometry = geometry.Clone();
geometry.Freeze();
}
return geometry;
}
}
///
/// Return the transformation applied to the geometry before rendering
///
public virtual Transform GeometryTransform
{
get
{
BoxedMatrix stretchMatrix = StretchMatrixField.GetValue(this);
if (stretchMatrix == null)
{
return Transform.Identity;
}
else
{
return new MatrixTransform(stretchMatrix.Value);
}
}
}
private static void OnPenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// Called when any of the Stroke properties is invalidated.
// That means that the cached pen should be recalculated.
((Shape)d)._pen = null;
}
///
/// Fill property
///
[CommonDependencyProperty]
public static readonly DependencyProperty FillProperty =
DependencyProperty.Register(
"Fill",
typeof(Brush),
typeof(Shape),
new FrameworkPropertyMetadata(
(Brush) null,
FrameworkPropertyMetadataOptions.AffectsRender |
FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender));
///
/// Fill property
///
public Brush Fill
{
get { return (Brush) GetValue(FillProperty); }
set { SetValue(FillProperty, value); }
}
///
/// Stroke property
///
[CommonDependencyProperty]
public static readonly DependencyProperty StrokeProperty =
DependencyProperty.Register(
"Stroke",
typeof(Brush),
typeof(Shape),
new FrameworkPropertyMetadata(
(Brush) null,
FrameworkPropertyMetadataOptions.AffectsMeasure |
FrameworkPropertyMetadataOptions.AffectsRender |
FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender,
new PropertyChangedCallback(OnPenChanged)));
///
/// Stroke property
///
public Brush Stroke
{
get { return (Brush) GetValue(StrokeProperty); }
set { SetValue(StrokeProperty, value); }
}
///
/// StrokeThickness property
///
[CommonDependencyProperty]
public static readonly DependencyProperty StrokeThicknessProperty =
DependencyProperty.Register(
"StrokeThickness",
typeof(double),
typeof(Shape),
new FrameworkPropertyMetadata(
1.0d,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnPenChanged)));
///
/// StrokeThickness property
///
[TypeConverter(typeof(LengthConverter))]
public double StrokeThickness
{
get { return (double) GetValue(StrokeThicknessProperty); }
set { SetValue(StrokeThicknessProperty, value); }
}
///
/// StrokeStartLineCap property
///
public static readonly DependencyProperty StrokeStartLineCapProperty =
DependencyProperty.Register(
"StrokeStartLineCap",
typeof(PenLineCap),
typeof(Shape),
new FrameworkPropertyMetadata(
PenLineCap.Flat,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnPenChanged)),
new ValidateValueCallback(System.Windows.Media.ValidateEnums.IsPenLineCapValid));
///
/// StrokeStartLineCap property
///
public PenLineCap StrokeStartLineCap
{
get { return (PenLineCap) GetValue(StrokeStartLineCapProperty); }
set { SetValue(StrokeStartLineCapProperty, value); }
}
///
/// StrokeEndLineCap property
///
public static readonly DependencyProperty StrokeEndLineCapProperty =
DependencyProperty.Register(
"StrokeEndLineCap",
typeof(PenLineCap),
typeof(Shape),
new FrameworkPropertyMetadata(
PenLineCap.Flat,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnPenChanged)),
new ValidateValueCallback(System.Windows.Media.ValidateEnums.IsPenLineCapValid));
///
/// StrokeEndLineCap property
///
public PenLineCap StrokeEndLineCap
{
get { return (PenLineCap) GetValue(StrokeEndLineCapProperty); }
set { SetValue(StrokeEndLineCapProperty, value); }
}
///
/// StrokeDashCap property
///
public static readonly DependencyProperty StrokeDashCapProperty =
DependencyProperty.Register(
"StrokeDashCap",
typeof(PenLineCap),
typeof(Shape),
new FrameworkPropertyMetadata(
PenLineCap.Flat,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnPenChanged)),
new ValidateValueCallback(System.Windows.Media.ValidateEnums.IsPenLineCapValid));
///
/// StrokeDashCap property
///
public PenLineCap StrokeDashCap
{
get { return (PenLineCap) GetValue(StrokeDashCapProperty); }
set { SetValue(StrokeDashCapProperty, value); }
}
///
/// StrokeLineJoin property
///
public static readonly DependencyProperty StrokeLineJoinProperty =
DependencyProperty.Register(
"StrokeLineJoin",
typeof(PenLineJoin),
typeof(Shape),
new FrameworkPropertyMetadata(
PenLineJoin.Miter,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnPenChanged)),
new ValidateValueCallback(System.Windows.Media.ValidateEnums.IsPenLineJoinValid));
///
/// StrokeLineJoin property
///
public PenLineJoin StrokeLineJoin
{
get { return (PenLineJoin) GetValue(StrokeLineJoinProperty); }
set { SetValue(StrokeLineJoinProperty, value); }
}
///
/// StrokeMiterLimit property
///
public static readonly DependencyProperty StrokeMiterLimitProperty =
DependencyProperty.Register(
"StrokeMiterLimit",
typeof(double),
typeof(Shape),
new FrameworkPropertyMetadata(
10.0,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnPenChanged)));
///
/// StrokeMiterLimit property
///
public double StrokeMiterLimit
{
get { return (double) GetValue(StrokeMiterLimitProperty); }
set { SetValue(StrokeMiterLimitProperty, value); }
}
///
/// StrokeDashOffset property
///
public static readonly DependencyProperty StrokeDashOffsetProperty =
DependencyProperty.Register(
"StrokeDashOffset",
typeof(double),
typeof(Shape),
new FrameworkPropertyMetadata(
0.0,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnPenChanged)));
///
/// StrokeDashOffset property
///
public double StrokeDashOffset
{
get { return (double) GetValue(StrokeDashOffsetProperty); }
set { SetValue(StrokeDashOffsetProperty, value); }
}
///
/// StrokeDashArray property
///
public static readonly DependencyProperty StrokeDashArrayProperty =
DependencyProperty.Register(
"StrokeDashArray",
typeof(DoubleCollection),
typeof(Shape),
new FrameworkPropertyMetadata(
new FreezableDefaultValueFactory(DoubleCollection.Empty),
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnPenChanged)));
///
/// StrokeDashArray property
///
public DoubleCollection StrokeDashArray
{
get { return (DoubleCollection) GetValue(StrokeDashArrayProperty); }
set { SetValue(StrokeDashArrayProperty, value); }
}
#endregion
#region Protected Methods
///
/// Updates DesiredSize of the shape. Called by parent UIElement during is the first pass of layout.
///
/// Constraint size is an "upper limit" that should not exceed.
/// Shape's desired size.
protected override Size MeasureOverride(Size constraint)
{
CacheDefiningGeometry();
Size newSize;
Stretch mode = Stretch;
if (mode == Stretch.None)
{
newSize = GetNaturalSize();
}
else
{
newSize = GetStretchedRenderSize(mode, GetStrokeThickness(), constraint, GetDefiningGeometryBounds());
}
if (SizeIsInvalidOrEmpty(newSize))
{
// We've encountered a numerical error. Don't draw anything.
newSize = new Size(0,0);
_renderedGeometry = Geometry.Empty;
}
return newSize;
}
///
/// Compute the rendered geometry and the stretching transform.
///
protected override Size ArrangeOverride(Size finalSize)
{
Size newSize;
Stretch mode = Stretch;
if (mode == Stretch.None)
{
StretchMatrixField.ClearValue(this);
ResetRenderedGeometry();
newSize = finalSize;
}
else
{
newSize = GetStretchedRenderSizeAndSetStretchMatrix(
mode, GetStrokeThickness(), finalSize, GetDefiningGeometryBounds());
}
if (SizeIsInvalidOrEmpty(newSize))
{
// We've encountered a numerical error. Don't draw anything.
newSize = new Size(0,0);
_renderedGeometry = Geometry.Empty;
}
return newSize;
}
///
/// Render callback.
///
protected override void OnRender(DrawingContext drawingContext)
{
EnsureRenderedGeometry();
if (_renderedGeometry != Geometry.Empty)
{
drawingContext.DrawGeometry(Fill, GetPen(), _renderedGeometry);
}
}
#endregion
#region Protected Properties
///
/// Get the geometry that defines this shape
///
protected abstract Geometry DefiningGeometry
{
get;
}
#endregion Protected Properties
#region Internal Methods
internal bool SizeIsInvalidOrEmpty(Size size)
{
return (DoubleUtil.IsNaN(size.Width) ||
DoubleUtil.IsNaN(size.Height) ||
size.IsEmpty);
}
internal bool IsPenNoOp
{
get
{
double strokeThickness = StrokeThickness;
return (Stroke == null) || DoubleUtil.IsNaN(strokeThickness) || DoubleUtil.IsZero(strokeThickness);
}
}
internal double GetStrokeThickness()
{
if (IsPenNoOp)
{
return 0;
}
else
{
return Math.Abs(StrokeThickness);
}
}
internal Pen GetPen()
{
if (IsPenNoOp)
{
return null;
}
if (_pen == null)
{
double thickness = 0.0;
double strokeThickness = StrokeThickness;
thickness = Math.Abs(strokeThickness);
// This pen is internal to the system and
// must not participate in freezable treeness
_pen = new Pen();
_pen.CanBeInheritanceContext = false;
_pen.Thickness = thickness;
_pen.Brush = Stroke;
_pen.StartLineCap = StrokeStartLineCap;
_pen.EndLineCap = StrokeEndLineCap;
_pen.DashCap = StrokeDashCap;
_pen.LineJoin = StrokeLineJoin;
_pen.MiterLimit = StrokeMiterLimit;
// StrokeDashArray is usually going to be its default value and GetValue
// on a mutable default has a per-instance cost associated with it so we'll
// try to avoid caching the default value
DoubleCollection strokeDashArray = null;
bool hasModifiers;
if (GetValueSource(StrokeDashArrayProperty, null, out hasModifiers)
!= BaseValueSourceInternal.Default || hasModifiers)
{
strokeDashArray = StrokeDashArray;
}
// Avoid creating the DashStyle if we can
double strokeDashOffset = StrokeDashOffset;
if (strokeDashArray != null || strokeDashOffset != 0.0)
{
_pen.DashStyle = new DashStyle(strokeDashArray, strokeDashOffset);
}
}
return _pen;
}
// Double verification helpers. Property system will verify type for us; we only need to verify the value.
internal static bool IsDoubleFiniteNonNegative(object o)
{
double d = (double)o;
return !(Double.IsInfinity(d) || DoubleUtil.IsNaN(d) || d < 0.0);
}
internal static bool IsDoubleFinite(object o)
{
double d = (double)o;
return !(Double.IsInfinity(d) || DoubleUtil.IsNaN(d));
}
internal static bool IsDoubleFiniteOrNaN(object o)
{
double d = (double)o;
return !(Double.IsInfinity(d));
}
internal virtual void CacheDefiningGeometry() {}
internal Size GetStretchedRenderSize(Stretch mode, double strokeThickness, Size availableSize, Rect geometryBounds)
{
double xScale, yScale, dX, dY;
Size renderSize;
GetStretchMetrics(mode, strokeThickness, availableSize, geometryBounds,
out xScale, out yScale, out dX, out dY, out renderSize);
return renderSize;
}
internal Size GetStretchedRenderSizeAndSetStretchMatrix(Stretch mode, double strokeThickness, Size availableSize, Rect geometryBounds)
{
double xScale, yScale, dX, dY;
Size renderSize;
GetStretchMetrics(mode, strokeThickness, availableSize, geometryBounds,
out xScale, out yScale, out dX, out dY, out renderSize);
// Construct the matrix
Matrix stretchMatrix = Matrix.Identity;
stretchMatrix.ScaleAt(xScale, yScale, geometryBounds.Location.X, geometryBounds.Location.Y);
stretchMatrix.Translate(dX, dY);
StretchMatrixField.SetValue(this, new BoxedMatrix(stretchMatrix));
ResetRenderedGeometry();
return renderSize;
}
internal void ResetRenderedGeometry()
{
// reset rendered geometry
_renderedGeometry = null;
}
internal void GetStretchMetrics(Stretch mode, double strokeThickness, Size availableSize, Rect geometryBounds,
out double xScale, out double yScale, out double dX, out double dY, out Size stretchedSize)
{
if (!geometryBounds.IsEmpty)
{
double margin = strokeThickness / 2;
bool hasThinDimension = false;
// Initialization for mode == Fill
xScale = Math.Max(availableSize.Width - strokeThickness, 0);
yScale = Math.Max(availableSize.Height - strokeThickness, 0);
dX = margin - geometryBounds.Left;
dY = margin - geometryBounds.Top;
// Compute the scale factors from the geometry to the size.
// The scale factors are ratios, and they have already been initialize to the numerators.
// To prevent fp overflow, we need to make sure that numerator / denomiator < limit;
// To do that without actually deviding, we check that denominator > numerator / limit.
// We take 1/epsilon as the limit, so the check is denominator > numerator * epsilon
if (geometryBounds.Width > xScale * Double.Epsilon)
{
xScale /= geometryBounds.Width;
}
else
{
xScale = 1;
hasThinDimension = true;
}
if (geometryBounds.Height > yScale * Double.Epsilon)
{
yScale /= geometryBounds.Height;
}
else
{
yScale = 1;
hasThinDimension = true;
}
// Because this case was handled by the caller
Debug.Assert(mode != Stretch.None);
// We are initialized for Fill, but for the other modes
// If one of our dimensions is thin, uniform stretches are
// meaningless, so we treat the stretch as fill.
if (mode != Stretch.Fill && !hasThinDimension)
{
if (mode == Stretch.Uniform)
{
if (yScale > xScale)
{
// Resize to fit the size's width
yScale = xScale;
}
else // if xScale >= yScale
{
// Resize to fit the size's height
xScale = yScale;
}
}
else
{
Debug.Assert(mode == Stretch.UniformToFill);
if (xScale > yScale)
{
// Resize to fill the size vertically, spilling out horizontally
yScale = xScale;
}
else // if yScale >= xScale
{
// Resize to fill the size horizontally, spilling out vertically
xScale = yScale;
}
}
}
stretchedSize = new Size(geometryBounds.Width * xScale + strokeThickness, geometryBounds.Height * yScale + strokeThickness);
}
else
{
xScale = yScale = 1;
dX = dY = 0;
stretchedSize = new Size(0,0);
}
}
///
/// Get the natural size of the geometry that defines this shape
///
internal virtual Size GetNaturalSize()
{
Geometry geometry = DefiningGeometry;
Debug.Assert(geometry != null);
//
// For the purposes of computing layout size, don't consider dashing. This will give us
// slightly different bounds, but the computation will be faster and more stable.
//
// NOTE: If GetPen() is ever made public, we will need to change this logic so the user
// isn't affected by our surreptitious change of DashStyle.
//
Pen pen = GetPen();
DashStyle style = null;
if (pen != null)
{
style = pen.DashStyle;
if (style != null)
{
pen.DashStyle = null;
}
}
Rect bounds = geometry.GetRenderBounds(pen);
if (style != null)
{
pen.DashStyle = style;
}
return new Size(Math.Max(bounds.Right, 0),
Math.Max(bounds.Bottom, 0));
}
///
/// Get the bonds of the geometry that defines this shape
///
internal virtual Rect GetDefiningGeometryBounds()
{
Geometry geometry = DefiningGeometry;
Debug.Assert(geometry != null);
return geometry.Bounds;
}
internal void EnsureRenderedGeometry()
{
if (_renderedGeometry == null)
{
_renderedGeometry = DefiningGeometry;
Debug.Assert(_renderedGeometry != null);
if (Stretch != Stretch.None)
{
Geometry currentValue = _renderedGeometry.CloneCurrentValue();
if (Object.ReferenceEquals(_renderedGeometry, currentValue))
{
_renderedGeometry = currentValue.Clone();
}
else
{
_renderedGeometry = currentValue;
}
Transform renderedTransform = _renderedGeometry.Transform;
BoxedMatrix boxedStretchMatrix = StretchMatrixField.GetValue(this);
Matrix stretchMatrix = (boxedStretchMatrix == null) ? Matrix.Identity : boxedStretchMatrix.Value;
if (renderedTransform == null || renderedTransform.IsIdentity)
{
_renderedGeometry.Transform = new MatrixTransform(stretchMatrix);
}
else
{
_renderedGeometry.Transform = new MatrixTransform(renderedTransform.Value * stretchMatrix);
}
}
}
}
#endregion Internal Methods
#region Private Fields
private Pen _pen = null;
private Geometry _renderedGeometry = Geometry.Empty;
private static UncommonField StretchMatrixField = new UncommonField(null);
#endregion Private Fields
}
internal class BoxedMatrix
{
public BoxedMatrix(Matrix value)
{
Value = value;
}
public Matrix Value;
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//----------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Description: Shape element is a base class for shapes like Path,
// Rectangle, GlyphRun etc.
//
// History:
//
// 06/02/2003 : mleonov - created.
// 07/29/2004 : timothyc - Added ValidateValueCallback for enumeration
// properties
//
//---------------------------------------------------------------------------
using System.Diagnostics;
using System.Windows.Threading;
using System.Windows;
using System.Windows.Media;
using System.ComponentModel;
using MS.Internal;
using MS.Internal.PresentationFramework;
using System;
namespace System.Windows.Shapes
{
///
/// Shape is a base class for shape elements
///
[Localizability(LocalizationCategory.None, Readability=Readability.Unreadable)]
public abstract class Shape : FrameworkElement
{
#region Constructors
///
/// Shape Constructor
///
protected Shape()
{
}
#endregion
#region Properties
///
/// DependencyProperty for the Stretch property.
///
public static readonly DependencyProperty StretchProperty
= DependencyProperty.Register(
"Stretch", // Property name
typeof(Stretch), // Property type
typeof(Shape), // Property owner
new FrameworkPropertyMetadata(Stretch.None, FrameworkPropertyMetadataOptions.AffectsArrange));
///
/// The Stretch property determines how the shape may be stretched to accommodate shape size
///
public Stretch Stretch
{
get { return (Stretch)GetValue(StretchProperty); }
set { SetValue(StretchProperty, value); }
}
///
/// The RenderedGeometry property returns the final rendered geometry
///
public virtual Geometry RenderedGeometry
{
get
{
EnsureRenderedGeometry();
Geometry geometry = _renderedGeometry.CloneCurrentValue();
if (geometry == null || geometry == Geometry.Empty)
{
return Geometry.Empty;
}
// We need to return a frozen copy
if (Object.ReferenceEquals(geometry, _renderedGeometry))
{
// geometry is a reference to _renderedGeometry, so we need to copy
geometry = geometry.Clone();
geometry.Freeze();
}
return geometry;
}
}
///
/// Return the transformation applied to the geometry before rendering
///
public virtual Transform GeometryTransform
{
get
{
BoxedMatrix stretchMatrix = StretchMatrixField.GetValue(this);
if (stretchMatrix == null)
{
return Transform.Identity;
}
else
{
return new MatrixTransform(stretchMatrix.Value);
}
}
}
private static void OnPenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// Called when any of the Stroke properties is invalidated.
// That means that the cached pen should be recalculated.
((Shape)d)._pen = null;
}
///
/// Fill property
///
[CommonDependencyProperty]
public static readonly DependencyProperty FillProperty =
DependencyProperty.Register(
"Fill",
typeof(Brush),
typeof(Shape),
new FrameworkPropertyMetadata(
(Brush) null,
FrameworkPropertyMetadataOptions.AffectsRender |
FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender));
///
/// Fill property
///
public Brush Fill
{
get { return (Brush) GetValue(FillProperty); }
set { SetValue(FillProperty, value); }
}
///
/// Stroke property
///
[CommonDependencyProperty]
public static readonly DependencyProperty StrokeProperty =
DependencyProperty.Register(
"Stroke",
typeof(Brush),
typeof(Shape),
new FrameworkPropertyMetadata(
(Brush) null,
FrameworkPropertyMetadataOptions.AffectsMeasure |
FrameworkPropertyMetadataOptions.AffectsRender |
FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender,
new PropertyChangedCallback(OnPenChanged)));
///
/// Stroke property
///
public Brush Stroke
{
get { return (Brush) GetValue(StrokeProperty); }
set { SetValue(StrokeProperty, value); }
}
///
/// StrokeThickness property
///
[CommonDependencyProperty]
public static readonly DependencyProperty StrokeThicknessProperty =
DependencyProperty.Register(
"StrokeThickness",
typeof(double),
typeof(Shape),
new FrameworkPropertyMetadata(
1.0d,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnPenChanged)));
///
/// StrokeThickness property
///
[TypeConverter(typeof(LengthConverter))]
public double StrokeThickness
{
get { return (double) GetValue(StrokeThicknessProperty); }
set { SetValue(StrokeThicknessProperty, value); }
}
///
/// StrokeStartLineCap property
///
public static readonly DependencyProperty StrokeStartLineCapProperty =
DependencyProperty.Register(
"StrokeStartLineCap",
typeof(PenLineCap),
typeof(Shape),
new FrameworkPropertyMetadata(
PenLineCap.Flat,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnPenChanged)),
new ValidateValueCallback(System.Windows.Media.ValidateEnums.IsPenLineCapValid));
///
/// StrokeStartLineCap property
///
public PenLineCap StrokeStartLineCap
{
get { return (PenLineCap) GetValue(StrokeStartLineCapProperty); }
set { SetValue(StrokeStartLineCapProperty, value); }
}
///
/// StrokeEndLineCap property
///
public static readonly DependencyProperty StrokeEndLineCapProperty =
DependencyProperty.Register(
"StrokeEndLineCap",
typeof(PenLineCap),
typeof(Shape),
new FrameworkPropertyMetadata(
PenLineCap.Flat,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnPenChanged)),
new ValidateValueCallback(System.Windows.Media.ValidateEnums.IsPenLineCapValid));
///
/// StrokeEndLineCap property
///
public PenLineCap StrokeEndLineCap
{
get { return (PenLineCap) GetValue(StrokeEndLineCapProperty); }
set { SetValue(StrokeEndLineCapProperty, value); }
}
///
/// StrokeDashCap property
///
public static readonly DependencyProperty StrokeDashCapProperty =
DependencyProperty.Register(
"StrokeDashCap",
typeof(PenLineCap),
typeof(Shape),
new FrameworkPropertyMetadata(
PenLineCap.Flat,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnPenChanged)),
new ValidateValueCallback(System.Windows.Media.ValidateEnums.IsPenLineCapValid));
///
/// StrokeDashCap property
///
public PenLineCap StrokeDashCap
{
get { return (PenLineCap) GetValue(StrokeDashCapProperty); }
set { SetValue(StrokeDashCapProperty, value); }
}
///
/// StrokeLineJoin property
///
public static readonly DependencyProperty StrokeLineJoinProperty =
DependencyProperty.Register(
"StrokeLineJoin",
typeof(PenLineJoin),
typeof(Shape),
new FrameworkPropertyMetadata(
PenLineJoin.Miter,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnPenChanged)),
new ValidateValueCallback(System.Windows.Media.ValidateEnums.IsPenLineJoinValid));
///
/// StrokeLineJoin property
///
public PenLineJoin StrokeLineJoin
{
get { return (PenLineJoin) GetValue(StrokeLineJoinProperty); }
set { SetValue(StrokeLineJoinProperty, value); }
}
///
/// StrokeMiterLimit property
///
public static readonly DependencyProperty StrokeMiterLimitProperty =
DependencyProperty.Register(
"StrokeMiterLimit",
typeof(double),
typeof(Shape),
new FrameworkPropertyMetadata(
10.0,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnPenChanged)));
///
/// StrokeMiterLimit property
///
public double StrokeMiterLimit
{
get { return (double) GetValue(StrokeMiterLimitProperty); }
set { SetValue(StrokeMiterLimitProperty, value); }
}
///
/// StrokeDashOffset property
///
public static readonly DependencyProperty StrokeDashOffsetProperty =
DependencyProperty.Register(
"StrokeDashOffset",
typeof(double),
typeof(Shape),
new FrameworkPropertyMetadata(
0.0,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnPenChanged)));
///
/// StrokeDashOffset property
///
public double StrokeDashOffset
{
get { return (double) GetValue(StrokeDashOffsetProperty); }
set { SetValue(StrokeDashOffsetProperty, value); }
}
///
/// StrokeDashArray property
///
public static readonly DependencyProperty StrokeDashArrayProperty =
DependencyProperty.Register(
"StrokeDashArray",
typeof(DoubleCollection),
typeof(Shape),
new FrameworkPropertyMetadata(
new FreezableDefaultValueFactory(DoubleCollection.Empty),
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnPenChanged)));
///
/// StrokeDashArray property
///
public DoubleCollection StrokeDashArray
{
get { return (DoubleCollection) GetValue(StrokeDashArrayProperty); }
set { SetValue(StrokeDashArrayProperty, value); }
}
#endregion
#region Protected Methods
///
/// Updates DesiredSize of the shape. Called by parent UIElement during is the first pass of layout.
///
/// Constraint size is an "upper limit" that should not exceed.
/// Shape's desired size.
protected override Size MeasureOverride(Size constraint)
{
CacheDefiningGeometry();
Size newSize;
Stretch mode = Stretch;
if (mode == Stretch.None)
{
newSize = GetNaturalSize();
}
else
{
newSize = GetStretchedRenderSize(mode, GetStrokeThickness(), constraint, GetDefiningGeometryBounds());
}
if (SizeIsInvalidOrEmpty(newSize))
{
// We've encountered a numerical error. Don't draw anything.
newSize = new Size(0,0);
_renderedGeometry = Geometry.Empty;
}
return newSize;
}
///
/// Compute the rendered geometry and the stretching transform.
///
protected override Size ArrangeOverride(Size finalSize)
{
Size newSize;
Stretch mode = Stretch;
if (mode == Stretch.None)
{
StretchMatrixField.ClearValue(this);
ResetRenderedGeometry();
newSize = finalSize;
}
else
{
newSize = GetStretchedRenderSizeAndSetStretchMatrix(
mode, GetStrokeThickness(), finalSize, GetDefiningGeometryBounds());
}
if (SizeIsInvalidOrEmpty(newSize))
{
// We've encountered a numerical error. Don't draw anything.
newSize = new Size(0,0);
_renderedGeometry = Geometry.Empty;
}
return newSize;
}
///
/// Render callback.
///
protected override void OnRender(DrawingContext drawingContext)
{
EnsureRenderedGeometry();
if (_renderedGeometry != Geometry.Empty)
{
drawingContext.DrawGeometry(Fill, GetPen(), _renderedGeometry);
}
}
#endregion
#region Protected Properties
///
/// Get the geometry that defines this shape
///
protected abstract Geometry DefiningGeometry
{
get;
}
#endregion Protected Properties
#region Internal Methods
internal bool SizeIsInvalidOrEmpty(Size size)
{
return (DoubleUtil.IsNaN(size.Width) ||
DoubleUtil.IsNaN(size.Height) ||
size.IsEmpty);
}
internal bool IsPenNoOp
{
get
{
double strokeThickness = StrokeThickness;
return (Stroke == null) || DoubleUtil.IsNaN(strokeThickness) || DoubleUtil.IsZero(strokeThickness);
}
}
internal double GetStrokeThickness()
{
if (IsPenNoOp)
{
return 0;
}
else
{
return Math.Abs(StrokeThickness);
}
}
internal Pen GetPen()
{
if (IsPenNoOp)
{
return null;
}
if (_pen == null)
{
double thickness = 0.0;
double strokeThickness = StrokeThickness;
thickness = Math.Abs(strokeThickness);
// This pen is internal to the system and
// must not participate in freezable treeness
_pen = new Pen();
_pen.CanBeInheritanceContext = false;
_pen.Thickness = thickness;
_pen.Brush = Stroke;
_pen.StartLineCap = StrokeStartLineCap;
_pen.EndLineCap = StrokeEndLineCap;
_pen.DashCap = StrokeDashCap;
_pen.LineJoin = StrokeLineJoin;
_pen.MiterLimit = StrokeMiterLimit;
// StrokeDashArray is usually going to be its default value and GetValue
// on a mutable default has a per-instance cost associated with it so we'll
// try to avoid caching the default value
DoubleCollection strokeDashArray = null;
bool hasModifiers;
if (GetValueSource(StrokeDashArrayProperty, null, out hasModifiers)
!= BaseValueSourceInternal.Default || hasModifiers)
{
strokeDashArray = StrokeDashArray;
}
// Avoid creating the DashStyle if we can
double strokeDashOffset = StrokeDashOffset;
if (strokeDashArray != null || strokeDashOffset != 0.0)
{
_pen.DashStyle = new DashStyle(strokeDashArray, strokeDashOffset);
}
}
return _pen;
}
// Double verification helpers. Property system will verify type for us; we only need to verify the value.
internal static bool IsDoubleFiniteNonNegative(object o)
{
double d = (double)o;
return !(Double.IsInfinity(d) || DoubleUtil.IsNaN(d) || d < 0.0);
}
internal static bool IsDoubleFinite(object o)
{
double d = (double)o;
return !(Double.IsInfinity(d) || DoubleUtil.IsNaN(d));
}
internal static bool IsDoubleFiniteOrNaN(object o)
{
double d = (double)o;
return !(Double.IsInfinity(d));
}
internal virtual void CacheDefiningGeometry() {}
internal Size GetStretchedRenderSize(Stretch mode, double strokeThickness, Size availableSize, Rect geometryBounds)
{
double xScale, yScale, dX, dY;
Size renderSize;
GetStretchMetrics(mode, strokeThickness, availableSize, geometryBounds,
out xScale, out yScale, out dX, out dY, out renderSize);
return renderSize;
}
internal Size GetStretchedRenderSizeAndSetStretchMatrix(Stretch mode, double strokeThickness, Size availableSize, Rect geometryBounds)
{
double xScale, yScale, dX, dY;
Size renderSize;
GetStretchMetrics(mode, strokeThickness, availableSize, geometryBounds,
out xScale, out yScale, out dX, out dY, out renderSize);
// Construct the matrix
Matrix stretchMatrix = Matrix.Identity;
stretchMatrix.ScaleAt(xScale, yScale, geometryBounds.Location.X, geometryBounds.Location.Y);
stretchMatrix.Translate(dX, dY);
StretchMatrixField.SetValue(this, new BoxedMatrix(stretchMatrix));
ResetRenderedGeometry();
return renderSize;
}
internal void ResetRenderedGeometry()
{
// reset rendered geometry
_renderedGeometry = null;
}
internal void GetStretchMetrics(Stretch mode, double strokeThickness, Size availableSize, Rect geometryBounds,
out double xScale, out double yScale, out double dX, out double dY, out Size stretchedSize)
{
if (!geometryBounds.IsEmpty)
{
double margin = strokeThickness / 2;
bool hasThinDimension = false;
// Initialization for mode == Fill
xScale = Math.Max(availableSize.Width - strokeThickness, 0);
yScale = Math.Max(availableSize.Height - strokeThickness, 0);
dX = margin - geometryBounds.Left;
dY = margin - geometryBounds.Top;
// Compute the scale factors from the geometry to the size.
// The scale factors are ratios, and they have already been initialize to the numerators.
// To prevent fp overflow, we need to make sure that numerator / denomiator < limit;
// To do that without actually deviding, we check that denominator > numerator / limit.
// We take 1/epsilon as the limit, so the check is denominator > numerator * epsilon
if (geometryBounds.Width > xScale * Double.Epsilon)
{
xScale /= geometryBounds.Width;
}
else
{
xScale = 1;
hasThinDimension = true;
}
if (geometryBounds.Height > yScale * Double.Epsilon)
{
yScale /= geometryBounds.Height;
}
else
{
yScale = 1;
hasThinDimension = true;
}
// Because this case was handled by the caller
Debug.Assert(mode != Stretch.None);
// We are initialized for Fill, but for the other modes
// If one of our dimensions is thin, uniform stretches are
// meaningless, so we treat the stretch as fill.
if (mode != Stretch.Fill && !hasThinDimension)
{
if (mode == Stretch.Uniform)
{
if (yScale > xScale)
{
// Resize to fit the size's width
yScale = xScale;
}
else // if xScale >= yScale
{
// Resize to fit the size's height
xScale = yScale;
}
}
else
{
Debug.Assert(mode == Stretch.UniformToFill);
if (xScale > yScale)
{
// Resize to fill the size vertically, spilling out horizontally
yScale = xScale;
}
else // if yScale >= xScale
{
// Resize to fill the size horizontally, spilling out vertically
xScale = yScale;
}
}
}
stretchedSize = new Size(geometryBounds.Width * xScale + strokeThickness, geometryBounds.Height * yScale + strokeThickness);
}
else
{
xScale = yScale = 1;
dX = dY = 0;
stretchedSize = new Size(0,0);
}
}
///
/// Get the natural size of the geometry that defines this shape
///
internal virtual Size GetNaturalSize()
{
Geometry geometry = DefiningGeometry;
Debug.Assert(geometry != null);
//
// For the purposes of computing layout size, don't consider dashing. This will give us
// slightly different bounds, but the computation will be faster and more stable.
//
// NOTE: If GetPen() is ever made public, we will need to change this logic so the user
// isn't affected by our surreptitious change of DashStyle.
//
Pen pen = GetPen();
DashStyle style = null;
if (pen != null)
{
style = pen.DashStyle;
if (style != null)
{
pen.DashStyle = null;
}
}
Rect bounds = geometry.GetRenderBounds(pen);
if (style != null)
{
pen.DashStyle = style;
}
return new Size(Math.Max(bounds.Right, 0),
Math.Max(bounds.Bottom, 0));
}
///
/// Get the bonds of the geometry that defines this shape
///
internal virtual Rect GetDefiningGeometryBounds()
{
Geometry geometry = DefiningGeometry;
Debug.Assert(geometry != null);
return geometry.Bounds;
}
internal void EnsureRenderedGeometry()
{
if (_renderedGeometry == null)
{
_renderedGeometry = DefiningGeometry;
Debug.Assert(_renderedGeometry != null);
if (Stretch != Stretch.None)
{
Geometry currentValue = _renderedGeometry.CloneCurrentValue();
if (Object.ReferenceEquals(_renderedGeometry, currentValue))
{
_renderedGeometry = currentValue.Clone();
}
else
{
_renderedGeometry = currentValue;
}
Transform renderedTransform = _renderedGeometry.Transform;
BoxedMatrix boxedStretchMatrix = StretchMatrixField.GetValue(this);
Matrix stretchMatrix = (boxedStretchMatrix == null) ? Matrix.Identity : boxedStretchMatrix.Value;
if (renderedTransform == null || renderedTransform.IsIdentity)
{
_renderedGeometry.Transform = new MatrixTransform(stretchMatrix);
}
else
{
_renderedGeometry.Transform = new MatrixTransform(renderedTransform.Value * stretchMatrix);
}
}
}
}
#endregion Internal Methods
#region Private Fields
private Pen _pen = null;
private Geometry _renderedGeometry = Geometry.Empty;
private static UncommonField StretchMatrixField = new UncommonField(null);
#endregion Private Fields
}
internal class BoxedMatrix
{
public BoxedMatrix(Matrix value)
{
Value = value;
}
public Matrix Value;
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- GlobalizationAssembly.cs
- ProcessModelInfo.cs
- ToolStripSplitStackLayout.cs
- BitmapEffectInput.cs
- DataSetMappper.cs
- CommandEventArgs.cs
- CodeCommentStatement.cs
- AppDomainProtocolHandler.cs
- ZoomPercentageConverter.cs
- Helper.cs
- StylusPlugin.cs
- MergePropertyDescriptor.cs
- ToolboxDataAttribute.cs
- DocumentApplication.cs
- StructuredTypeEmitter.cs
- XmlILConstructAnalyzer.cs
- BindingContext.cs
- SQLMoney.cs
- X509CertificateCollection.cs
- _ProxyChain.cs
- ListViewSelectEventArgs.cs
- LazyTextWriterCreator.cs
- DataContext.cs
- TreeIterators.cs
- HitTestResult.cs
- MgmtConfigurationRecord.cs
- Help.cs
- ErrorFormatter.cs
- ParameterBuilder.cs
- ObjectPersistData.cs
- StrokeSerializer.cs
- ISAPIRuntime.cs
- XmlAttributes.cs
- MultitargetingHelpers.cs
- DesignerAttributeInfo.cs
- QueryCacheManager.cs
- OleDbInfoMessageEvent.cs
- StringBlob.cs
- Int16Animation.cs
- AccessorTable.cs
- EmptyStringExpandableObjectConverter.cs
- _ConnectionGroup.cs
- Vector3D.cs
- CompilerErrorCollection.cs
- PageRequestManager.cs
- StringWriter.cs
- ControlParameter.cs
- Point.cs
- ForeignKeyConstraint.cs
- CorrelationResolver.cs
- IssuanceLicense.cs
- KeyGestureConverter.cs
- MatrixCamera.cs
- EnumValAlphaComparer.cs
- ServiceObjectContainer.cs
- EntityException.cs
- SynchronizingStream.cs
- MD5CryptoServiceProvider.cs
- DiagnosticsElement.cs
- __Filters.cs
- HandleRef.cs
- SspiNegotiationTokenProvider.cs
- FormatException.cs
- SafeMarshalContext.cs
- UpdateProgress.cs
- IPHostEntry.cs
- XPathCompileException.cs
- AutomationEventArgs.cs
- SqlCacheDependencyDatabaseCollection.cs
- Emitter.cs
- ConnectionPointGlyph.cs
- TypeElement.cs
- RemoteWebConfigurationHostServer.cs
- EntityClassGenerator.cs
- BindingExpression.cs
- VisualCollection.cs
- Win32Exception.cs
- MappingMetadataHelper.cs
- ProcessThread.cs
- CompressionTracing.cs
- InternalControlCollection.cs
- Composition.cs
- FormViewAutoFormat.cs
- TransformerInfo.cs
- XmlUtilWriter.cs
- BindingsCollection.cs
- ExpressionEvaluator.cs
- Receive.cs
- CharacterMetrics.cs
- ColorTransformHelper.cs
- TreeSet.cs
- WebPartManager.cs
- WebHttpEndpointElement.cs
- CachedFontFamily.cs
- FrameSecurityDescriptor.cs
- CounterSample.cs
- CultureInfoConverter.cs
- OdbcConnectionPoolProviderInfo.cs
- StringConcat.cs
- PatternMatcher.cs