add DashBorder
This commit is contained in:
1 parent
096fa70ecb
commit
f367263379
2 files changed
+671
No files matched your search
@@ -0,0 +1,670 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Expression.Drawing;
|
||||
using HandyControl.Tools;
|
||||
using HandyControl.Tools.Extension;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
public class DashBorder : Decorator
|
||||
{
|
||||
private bool _useComplexRenderCodePath;
|
||||
|
||||
private Pen GeometryPenCache { get; set; }
|
||||
|
||||
private Pen LeftPenCache { get; set; }
|
||||
|
||||
private Pen RightPenCache { get; set; }
|
||||
|
||||
private Pen TopPenCache { get; set; }
|
||||
|
||||
private Pen BottomPenCache { get; set; }
|
||||
|
||||
private StreamGeometry BackgroundGeometryCache { get; set; }
|
||||
|
||||
private StreamGeometry BorderGeometryCache { get; set; }
|
||||
|
||||
private static void OnClearPenCache(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var border = (DashBorder)d;
|
||||
border.LeftPenCache = null;
|
||||
border.RightPenCache = null;
|
||||
border.TopPenCache = null;
|
||||
border.BottomPenCache = null;
|
||||
border.GeometryPenCache = null;
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty BorderThicknessProperty = DependencyProperty.Register(
|
||||
"BorderThickness", typeof(Thickness), typeof(DashBorder), new FrameworkPropertyMetadata(default(Thickness),
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
|
||||
OnClearPenCache));
|
||||
|
||||
public Thickness BorderThickness
|
||||
{
|
||||
get => (Thickness) GetValue(BorderThicknessProperty);
|
||||
set => SetValue(BorderThicknessProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty BorderDashThicknessProperty = DependencyProperty.Register(
|
||||
"BorderDashThickness", typeof(double), typeof(DashBorder), new FrameworkPropertyMetadata(ValueBoxes.Double0Box,
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
|
||||
OnClearPenCache));
|
||||
|
||||
public double BorderDashThickness
|
||||
{
|
||||
get => (double) GetValue(BorderDashThicknessProperty);
|
||||
set => SetValue(BorderDashThicknessProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty PaddingProperty = DependencyProperty.Register(
|
||||
"Padding", typeof(Thickness), typeof(DashBorder), new FrameworkPropertyMetadata(default(Thickness),
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public Thickness Padding
|
||||
{
|
||||
get => (Thickness) GetValue(PaddingProperty);
|
||||
set => SetValue(PaddingProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register(
|
||||
"CornerRadius", typeof(CornerRadius), typeof(DashBorder), new FrameworkPropertyMetadata(default(CornerRadius),
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public CornerRadius CornerRadius
|
||||
{
|
||||
get => (CornerRadius) GetValue(CornerRadiusProperty);
|
||||
set => SetValue(CornerRadiusProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty BorderBrushProperty = DependencyProperty.Register(
|
||||
"BorderBrush", typeof(Brush), typeof(DashBorder), new FrameworkPropertyMetadata(default(Brush),
|
||||
FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender,
|
||||
OnClearPenCache));
|
||||
|
||||
public Brush BorderBrush
|
||||
{
|
||||
get => (Brush) GetValue(BorderBrushProperty);
|
||||
set => SetValue(BorderBrushProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty BackgroundProperty = DependencyProperty.Register(
|
||||
"Background", typeof(Brush), typeof(DashBorder), new FrameworkPropertyMetadata(default(Brush),
|
||||
FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender,
|
||||
OnClearPenCache));
|
||||
|
||||
public Brush Background
|
||||
{
|
||||
get => (Brush) GetValue(BackgroundProperty);
|
||||
set => SetValue(BackgroundProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty BorderDashArrayProperty = DependencyProperty.Register(
|
||||
"BorderDashArray", typeof(DoubleCollection), typeof(DashBorder), new FrameworkPropertyMetadata(default(DoubleCollection),
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
|
||||
OnClearPenCache));
|
||||
|
||||
public DoubleCollection BorderDashArray
|
||||
{
|
||||
get => (DoubleCollection) GetValue(BorderDashArrayProperty);
|
||||
set => SetValue(BorderDashArrayProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty BorderDashCapProperty = DependencyProperty.Register(
|
||||
"BorderDashCap", typeof(PenLineCap), typeof(DashBorder), new FrameworkPropertyMetadata(default(PenLineCap),
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
|
||||
OnClearPenCache));
|
||||
|
||||
public PenLineCap BorderDashCap
|
||||
{
|
||||
get => (PenLineCap) GetValue(BorderDashCapProperty);
|
||||
set => SetValue(BorderDashCapProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty BorderDashOffsetProperty = DependencyProperty.Register(
|
||||
"BorderDashOffset", typeof(double), typeof(DashBorder), new FrameworkPropertyMetadata(ValueBoxes.Double0Box,
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
|
||||
OnClearPenCache));
|
||||
|
||||
public double BorderDashOffset
|
||||
{
|
||||
get => (double) GetValue(BorderDashOffsetProperty);
|
||||
set => SetValue(BorderDashOffsetProperty, value);
|
||||
}
|
||||
|
||||
private static Size ConvertThickness2Size(Thickness th) => new Size(th.Left + th.Right, th.Top + th.Bottom);
|
||||
|
||||
private static Rect DeflateRect(Rect rt, Thickness thick) => new Rect(rt.Left + thick.Left,
|
||||
rt.Top + thick.Top,
|
||||
Math.Max(0.0, rt.Width - thick.Left - thick.Right),
|
||||
Math.Max(0.0, rt.Height - thick.Top - thick.Bottom));
|
||||
|
||||
private static bool AreUniformCorners(CornerRadius borderRadii)
|
||||
{
|
||||
var topLeft = borderRadii.TopLeft;
|
||||
return MathHelper.AreClose(topLeft, borderRadii.TopRight) &&
|
||||
MathHelper.AreClose(topLeft, borderRadii.BottomLeft) &&
|
||||
MathHelper.AreClose(topLeft, borderRadii.BottomRight);
|
||||
}
|
||||
|
||||
private static void GenerateGeometry(StreamGeometryContext ctx, Rect rect, in Radii radii)
|
||||
{
|
||||
var topLeft = new Point(radii.LeftTop, 0);
|
||||
var topRight = new Point(rect.Width - radii.RightTop, 0);
|
||||
var rightTop = new Point(rect.Width, radii.TopRight);
|
||||
var rightBottom = new Point(rect.Width, rect.Height - radii.BottomRight);
|
||||
var bottomRight = new Point(rect.Width - radii.RightBottom, rect.Height);
|
||||
var bottomLeft = new Point(radii.LeftBottom, rect.Height);
|
||||
var leftBottom = new Point(0, rect.Height - radii.BottomLeft);
|
||||
var leftTop = new Point(0, radii.TopLeft);
|
||||
|
||||
// top edge
|
||||
if (topLeft.X > topRight.X)
|
||||
{
|
||||
var v = radii.LeftTop / (radii.LeftTop + radii.RightTop) * rect.Width;
|
||||
topLeft.X = v;
|
||||
topRight.X = v;
|
||||
}
|
||||
|
||||
// right edge
|
||||
if (rightTop.Y > rightBottom.Y)
|
||||
{
|
||||
var v = radii.TopRight / (radii.TopRight + radii.BottomRight) * rect.Height;
|
||||
rightTop.Y = v;
|
||||
rightBottom.Y = v;
|
||||
}
|
||||
|
||||
// bottom edge
|
||||
if (bottomRight.X < bottomLeft.X)
|
||||
{
|
||||
var v = radii.LeftBottom / (radii.LeftBottom + radii.RightBottom) * rect.Width;
|
||||
bottomRight.X = v;
|
||||
bottomLeft.X = v;
|
||||
}
|
||||
|
||||
// left edge
|
||||
if (leftBottom.Y < leftTop.Y)
|
||||
{
|
||||
var v = radii.TopLeft / (radii.TopLeft + radii.BottomLeft) * rect.Height;
|
||||
leftBottom.Y = v;
|
||||
leftTop.Y = v;
|
||||
}
|
||||
|
||||
// add on offsets
|
||||
var offset = new Vector(rect.TopLeft.X, rect.TopLeft.Y);
|
||||
topLeft += offset;
|
||||
topRight += offset;
|
||||
rightTop += offset;
|
||||
rightBottom += offset;
|
||||
bottomRight += offset;
|
||||
bottomLeft += offset;
|
||||
leftBottom += offset;
|
||||
leftTop += offset;
|
||||
|
||||
// create the border geometry
|
||||
ctx.BeginFigure(topLeft, true, true);
|
||||
|
||||
// Top line
|
||||
ctx.LineTo(topRight, true, false);
|
||||
|
||||
// Upper-right corner
|
||||
var radiusX = rect.TopRight.X - topRight.X;
|
||||
var radiusY = rightTop.Y - rect.TopRight.Y;
|
||||
if (!MathHelper.IsZero(radiusX) || !MathHelper.IsZero(radiusY))
|
||||
{
|
||||
ctx.ArcTo(rightTop, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false);
|
||||
}
|
||||
|
||||
// Right line
|
||||
ctx.LineTo(rightBottom, true, false);
|
||||
|
||||
// Lower-right corner
|
||||
radiusX = rect.BottomRight.X - bottomRight.X;
|
||||
radiusY = rect.BottomRight.Y - rightBottom.Y;
|
||||
if (!MathHelper.IsZero(radiusX) || !MathHelper.IsZero(radiusY))
|
||||
{
|
||||
ctx.ArcTo(bottomRight, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false);
|
||||
}
|
||||
|
||||
// Bottom line
|
||||
ctx.LineTo(bottomLeft, true, false);
|
||||
|
||||
// Lower-left corner
|
||||
radiusX = bottomLeft.X - rect.BottomLeft.X;
|
||||
radiusY = rect.BottomLeft.Y - leftBottom.Y;
|
||||
if (!MathHelper.IsZero(radiusX) || !MathHelper.IsZero(radiusY))
|
||||
{
|
||||
ctx.ArcTo(leftBottom, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false);
|
||||
}
|
||||
|
||||
// Left line
|
||||
ctx.LineTo(leftTop, true, false);
|
||||
|
||||
// Upper-left corner
|
||||
radiusX = topLeft.X - rect.TopLeft.X;
|
||||
radiusY = leftTop.Y - rect.TopLeft.Y;
|
||||
if (!MathHelper.IsZero(radiusX) || !MathHelper.IsZero(radiusY))
|
||||
{
|
||||
ctx.ArcTo(topLeft, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size constraint)
|
||||
{
|
||||
var child = Child;
|
||||
var borderThickness = BorderThickness;
|
||||
var padding = Padding;
|
||||
|
||||
if (UseLayoutRounding)
|
||||
{
|
||||
var dpiScaleX = DpiHelper.DeviceDpiX;
|
||||
var dpiScaleY = DpiHelper.DeviceDpiY;
|
||||
|
||||
borderThickness = new Thickness(
|
||||
DpiHelper.RoundLayoutValue(borderThickness.Left, dpiScaleX),
|
||||
DpiHelper.RoundLayoutValue(borderThickness.Top, dpiScaleY),
|
||||
DpiHelper.RoundLayoutValue(borderThickness.Right, dpiScaleX),
|
||||
DpiHelper.RoundLayoutValue(borderThickness.Bottom, dpiScaleY));
|
||||
}
|
||||
|
||||
var borderSize = ConvertThickness2Size(borderThickness);
|
||||
var paddingSize = ConvertThickness2Size(padding);
|
||||
var mySize = new Size();
|
||||
|
||||
if (child != null)
|
||||
{
|
||||
var combined = new Size(borderSize.Width + paddingSize.Width, borderSize.Height + paddingSize.Height);
|
||||
var childConstraint = new Size(Math.Max(0.0, constraint.Width - combined.Width), Math.Max(0.0, constraint.Height - combined.Height));
|
||||
|
||||
child.Measure(childConstraint);
|
||||
var childSize = child.DesiredSize;
|
||||
|
||||
mySize.Width = childSize.Width + combined.Width;
|
||||
mySize.Height = childSize.Height + combined.Height;
|
||||
}
|
||||
else
|
||||
{
|
||||
mySize = new Size(borderSize.Width + paddingSize.Width, borderSize.Height + paddingSize.Height);
|
||||
}
|
||||
|
||||
return mySize;
|
||||
}
|
||||
|
||||
protected override Size ArrangeOverride(Size arrangeSize)
|
||||
{
|
||||
var borderThickness = BorderThickness;
|
||||
|
||||
if (UseLayoutRounding)
|
||||
{
|
||||
var dpiScaleX = DpiHelper.DeviceDpiX;
|
||||
var dpiScaleY = DpiHelper.DeviceDpiY;
|
||||
|
||||
borderThickness = new Thickness(
|
||||
DpiHelper.RoundLayoutValue(borderThickness.Left, dpiScaleX),
|
||||
DpiHelper.RoundLayoutValue(borderThickness.Top, dpiScaleY),
|
||||
DpiHelper.RoundLayoutValue(borderThickness.Right, dpiScaleX),
|
||||
DpiHelper.RoundLayoutValue(borderThickness.Bottom, dpiScaleY));
|
||||
}
|
||||
|
||||
var boundRect = new Rect(arrangeSize);
|
||||
var innerRect = DeflateRect(boundRect, borderThickness);
|
||||
|
||||
var child = Child;
|
||||
if (child != null)
|
||||
{
|
||||
var padding = Padding;
|
||||
var childRect = DeflateRect(innerRect, padding);
|
||||
child.Arrange(childRect);
|
||||
}
|
||||
|
||||
var radii = CornerRadius;
|
||||
var borderBrush = BorderBrush;
|
||||
var uniformCorners = AreUniformCorners(radii);
|
||||
|
||||
_useComplexRenderCodePath = !uniformCorners;
|
||||
if (!_useComplexRenderCodePath && borderBrush != null)
|
||||
{
|
||||
_useComplexRenderCodePath = !MathHelper.IsZero(radii.TopLeft) && !borderThickness.IsUniform();
|
||||
}
|
||||
|
||||
if (_useComplexRenderCodePath)
|
||||
{
|
||||
var innerRadii = new Radii(radii, borderThickness, false);
|
||||
StreamGeometry backgroundGeometry = null;
|
||||
|
||||
if (!MathHelper.IsZero(innerRect.Width) && !MathHelper.IsZero(innerRect.Height))
|
||||
{
|
||||
backgroundGeometry = new StreamGeometry();
|
||||
|
||||
using (var ctx = backgroundGeometry.Open())
|
||||
{
|
||||
GenerateGeometry(ctx, innerRect, innerRadii);
|
||||
}
|
||||
|
||||
backgroundGeometry.Freeze();
|
||||
BackgroundGeometryCache = backgroundGeometry;
|
||||
}
|
||||
else
|
||||
{
|
||||
BackgroundGeometryCache = null;
|
||||
}
|
||||
|
||||
if (!MathHelper.IsZero(boundRect.Width) && !MathHelper.IsZero(boundRect.Height))
|
||||
{
|
||||
var outerRadii = new Radii(radii, borderThickness, true);
|
||||
var borderGeometry = new StreamGeometry();
|
||||
|
||||
using (var ctx = borderGeometry.Open())
|
||||
{
|
||||
GenerateGeometry(ctx, boundRect, outerRadii);
|
||||
|
||||
if (backgroundGeometry != null)
|
||||
{
|
||||
GenerateGeometry(ctx, innerRect, innerRadii);
|
||||
}
|
||||
}
|
||||
|
||||
borderGeometry.Freeze();
|
||||
BorderGeometryCache = borderGeometry;
|
||||
}
|
||||
else
|
||||
{
|
||||
BorderGeometryCache = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BackgroundGeometryCache = null;
|
||||
BorderGeometryCache = null;
|
||||
}
|
||||
|
||||
return arrangeSize;
|
||||
}
|
||||
|
||||
protected override void OnRender(DrawingContext drawingContext)
|
||||
{
|
||||
var background = Background;
|
||||
var borderBrush = BorderBrush;
|
||||
var useLayoutRounding = UseLayoutRounding;
|
||||
|
||||
if (_useComplexRenderCodePath)
|
||||
{
|
||||
var borderGeometry = BorderGeometryCache;
|
||||
if (borderGeometry != null && borderBrush != null)
|
||||
{
|
||||
var pen = GeometryPenCache;
|
||||
if (pen == null)
|
||||
{
|
||||
pen = new Pen
|
||||
{
|
||||
Brush = borderBrush,
|
||||
Thickness = BorderDashThickness,
|
||||
DashCap = BorderDashCap,
|
||||
DashStyle = new DashStyle(BorderDashArray, BorderDashOffset)
|
||||
};
|
||||
|
||||
if (borderBrush.IsFrozen)
|
||||
{
|
||||
pen.Freeze();
|
||||
}
|
||||
|
||||
GeometryPenCache = pen;
|
||||
}
|
||||
|
||||
drawingContext.DrawGeometry(null, pen, borderGeometry);
|
||||
}
|
||||
|
||||
var backgroundGeometry = BackgroundGeometryCache;
|
||||
if (backgroundGeometry != null && background != null)
|
||||
{
|
||||
drawingContext.DrawGeometry(background, null, backgroundGeometry);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var dpiScaleX = DpiHelper.DeviceDpiX;
|
||||
var dpiScaleY = DpiHelper.DeviceDpiY;
|
||||
|
||||
var borderThickness = BorderThickness;
|
||||
var cornerRadius = CornerRadius;
|
||||
var outerCornerRadius = cornerRadius.TopLeft;
|
||||
var roundedCorners = !MathHelper.IsZero(outerCornerRadius);
|
||||
|
||||
if (!borderThickness.IsZero() && borderBrush != null)
|
||||
{
|
||||
var pen = LeftPenCache;
|
||||
if (pen == null)
|
||||
{
|
||||
pen = new Pen
|
||||
{
|
||||
Brush = borderBrush,
|
||||
Thickness = useLayoutRounding
|
||||
? DpiHelper.RoundLayoutValue(borderThickness.Left, dpiScaleX)
|
||||
: borderThickness.Left,
|
||||
DashCap = BorderDashCap,
|
||||
DashStyle = new DashStyle(BorderDashArray, BorderDashOffset)
|
||||
};
|
||||
|
||||
if (borderBrush.IsFrozen)
|
||||
{
|
||||
pen.Freeze();
|
||||
}
|
||||
|
||||
LeftPenCache = pen;
|
||||
}
|
||||
|
||||
double halfThickness;
|
||||
var renderSize = RenderSize;
|
||||
|
||||
if (borderThickness.IsUniform())
|
||||
{
|
||||
halfThickness = pen.Thickness * 0.5;
|
||||
var rect = new Rect(new Point(halfThickness, halfThickness), new Point(renderSize.Width - halfThickness, renderSize.Height - halfThickness));
|
||||
|
||||
if (roundedCorners)
|
||||
{
|
||||
drawingContext.DrawRoundedRectangle(null, pen, rect, outerCornerRadius, outerCornerRadius);
|
||||
}
|
||||
else
|
||||
{
|
||||
drawingContext.DrawRectangle(null, pen, rect);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MathHelper.GreaterThan(borderThickness.Left, 0))
|
||||
{
|
||||
halfThickness = pen.Thickness * 0.5;
|
||||
drawingContext.DrawLine(pen, new Point(halfThickness, 0), new Point(halfThickness, renderSize.Height));
|
||||
}
|
||||
|
||||
if (MathHelper.GreaterThan(borderThickness.Right, 0))
|
||||
{
|
||||
pen = RightPenCache;
|
||||
if (pen == null)
|
||||
{
|
||||
pen = new Pen
|
||||
{
|
||||
Brush = borderBrush,
|
||||
Thickness = useLayoutRounding
|
||||
? DpiHelper.RoundLayoutValue(borderThickness.Right, dpiScaleX)
|
||||
: borderThickness.Right,
|
||||
DashCap = BorderDashCap,
|
||||
DashStyle = new DashStyle(BorderDashArray, BorderDashOffset)
|
||||
};
|
||||
|
||||
if (borderBrush.IsFrozen)
|
||||
{
|
||||
pen.Freeze();
|
||||
}
|
||||
|
||||
RightPenCache = pen;
|
||||
}
|
||||
|
||||
halfThickness = pen.Thickness * 0.5;
|
||||
drawingContext.DrawLine(pen, new Point(renderSize.Width - halfThickness, 0), new Point(renderSize.Width - halfThickness, renderSize.Height));
|
||||
}
|
||||
|
||||
if (MathHelper.GreaterThan(borderThickness.Top, 0))
|
||||
{
|
||||
pen = TopPenCache;
|
||||
if (pen == null)
|
||||
{
|
||||
pen = new Pen
|
||||
{
|
||||
Brush = borderBrush,
|
||||
Thickness = useLayoutRounding
|
||||
? DpiHelper.RoundLayoutValue(borderThickness.Top, dpiScaleY)
|
||||
: borderThickness.Top,
|
||||
DashCap = BorderDashCap,
|
||||
DashStyle = new DashStyle(BorderDashArray, BorderDashOffset)
|
||||
};
|
||||
|
||||
if (borderBrush.IsFrozen)
|
||||
{
|
||||
pen.Freeze();
|
||||
}
|
||||
|
||||
TopPenCache = pen;
|
||||
}
|
||||
|
||||
halfThickness = pen.Thickness * 0.5;
|
||||
drawingContext.DrawLine(pen, new Point(0, halfThickness), new Point(renderSize.Width, halfThickness));
|
||||
}
|
||||
|
||||
if (MathHelper.GreaterThan(borderThickness.Bottom, 0))
|
||||
{
|
||||
pen = BottomPenCache;
|
||||
if (pen == null)
|
||||
{
|
||||
pen = new Pen
|
||||
{
|
||||
Brush = borderBrush,
|
||||
Thickness = useLayoutRounding
|
||||
? DpiHelper.RoundLayoutValue(borderThickness.Bottom, dpiScaleY)
|
||||
: borderThickness.Bottom,
|
||||
DashCap = BorderDashCap,
|
||||
DashStyle = new DashStyle(BorderDashArray, BorderDashOffset)
|
||||
};
|
||||
|
||||
if (borderBrush.IsFrozen)
|
||||
{
|
||||
pen.Freeze();
|
||||
}
|
||||
|
||||
BottomPenCache = pen;
|
||||
}
|
||||
|
||||
halfThickness = pen.Thickness * 0.5;
|
||||
drawingContext.DrawLine(pen, new Point(0, renderSize.Height - halfThickness), new Point(renderSize.Width, renderSize.Height - halfThickness));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (background != null)
|
||||
{
|
||||
Point ptTL, ptBR;
|
||||
|
||||
if (useLayoutRounding)
|
||||
{
|
||||
ptTL = new Point(DpiHelper.RoundLayoutValue(borderThickness.Left, dpiScaleX), DpiHelper.RoundLayoutValue(borderThickness.Top, dpiScaleY));
|
||||
ptBR = new Point(RenderSize.Width - DpiHelper.RoundLayoutValue(borderThickness.Right, dpiScaleX),
|
||||
RenderSize.Height - DpiHelper.RoundLayoutValue(borderThickness.Bottom, dpiScaleY));
|
||||
}
|
||||
else
|
||||
{
|
||||
ptTL = new Point(borderThickness.Left, borderThickness.Top);
|
||||
ptBR = new Point(RenderSize.Width - borderThickness.Right, RenderSize.Height - borderThickness.Bottom);
|
||||
}
|
||||
|
||||
if (ptBR.X > ptTL.X && ptBR.Y > ptTL.Y)
|
||||
{
|
||||
if (roundedCorners)
|
||||
{
|
||||
var innerRadii = new Radii(cornerRadius, borderThickness, false);
|
||||
var innerCornerRadius = innerRadii.TopLeft;
|
||||
drawingContext.DrawRoundedRectangle(background, null, new Rect(ptTL, ptBR), innerCornerRadius, innerCornerRadius);
|
||||
}
|
||||
else
|
||||
{
|
||||
drawingContext.DrawRectangle(background, null, new Rect(ptTL, ptBR));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly struct Radii
|
||||
{
|
||||
internal Radii(CornerRadius radii, Thickness borders, bool outer)
|
||||
{
|
||||
var left = 0.5 * borders.Left;
|
||||
var top = 0.5 * borders.Top;
|
||||
var right = 0.5 * borders.Right;
|
||||
var bottom = 0.5 * borders.Bottom;
|
||||
|
||||
if (outer)
|
||||
{
|
||||
if (MathHelper.IsZero(radii.TopLeft))
|
||||
{
|
||||
LeftTop = TopLeft = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LeftTop = radii.TopLeft + left;
|
||||
TopLeft = radii.TopLeft + top;
|
||||
}
|
||||
if (MathHelper.IsZero(radii.TopRight))
|
||||
{
|
||||
TopRight = RightTop = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
TopRight = radii.TopRight + top;
|
||||
RightTop = radii.TopRight + right;
|
||||
}
|
||||
if (MathHelper.IsZero(radii.BottomRight))
|
||||
{
|
||||
RightBottom = BottomRight = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
RightBottom = radii.BottomRight + right;
|
||||
BottomRight = radii.BottomRight + bottom;
|
||||
}
|
||||
if (MathHelper.IsZero(radii.BottomLeft))
|
||||
{
|
||||
BottomLeft = LeftBottom = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
BottomLeft = radii.BottomLeft + bottom;
|
||||
LeftBottom = radii.BottomLeft + left;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LeftTop = Math.Max(0.0, radii.TopLeft - left);
|
||||
TopLeft = Math.Max(0.0, radii.TopLeft - top);
|
||||
TopRight = Math.Max(0.0, radii.TopRight - top);
|
||||
RightTop = Math.Max(0.0, radii.TopRight - right);
|
||||
RightBottom = Math.Max(0.0, radii.BottomRight - right);
|
||||
BottomRight = Math.Max(0.0, radii.BottomRight - bottom);
|
||||
BottomLeft = Math.Max(0.0, radii.BottomLeft - bottom);
|
||||
LeftBottom = Math.Max(0.0, radii.BottomLeft - left);
|
||||
}
|
||||
}
|
||||
|
||||
internal readonly double LeftTop;
|
||||
internal readonly double TopLeft;
|
||||
internal readonly double TopRight;
|
||||
internal readonly double RightTop;
|
||||
internal readonly double RightBottom;
|
||||
internal readonly double BottomRight;
|
||||
internal readonly double BottomLeft;
|
||||
internal readonly double LeftBottom;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Controls\Image\ImageBlock.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Controls\Input\ImageSelector.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Controls\Input\PinBox.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Controls\Other\DashBorder.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Controls\Other\Divider.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Controls\Other\Drawer.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Controls\Other\Magnifier.cs" />
|
||||
|
||||
Reference in new issue
Block a user