我有一个适应列和行的网格。 在该网格中,我必须绘制一条弧,该弧延伸并延伸到整个父网格。
我试过了
Canvas cnv = new Canvas();
Path pth = new Path() { HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch };
PathGeometry pg = new PathGeometry();
PathFigureCollection pfc = new PathFigureCollection();
PathFigure pf = new PathFigure();
ArcSegment a = new ArcSegment(new Point(0, 0), new Size(300, 300), 45, true, SweepDirection.Clockwise, true);
cnv.Children.Add(pth);
pth.Data = pg;
pfc.Add(pf);
pg.Figures = pfc;
pf.Segments.Add(a);
grd.Children.Add(cnv);
但没有出现。
此外,我想知道是否有更多的解决方案来实现目标。
然后,我不想设置弧的大小,我希望它延伸到父级大小,可能有一个余量。
非常感谢
答案 0 :(得分:2)
弧的目标点不应该是0,0。将其设置为有效点,同时设置Stroke
的{{1}}和Fill
属性:
Path
答案 1 :(得分:1)
如果您无法访问ActualWidth和ActualHeight,则网格仍然无法加载。我建议将代码放在gridLoaded事件中。 另外,我强烈建议使用that解决方案,以便更容易绘制弧线。
简而言之,在构造函数中:
grd.Loaded + = Grd_Loaded;
然后在事件被解雇后
private void Grd_Loaded(object sender, RoutedEventArgs e)
{
Canvas cnv = new Canvas();
Path pth = new Path();
pth.Fill = Brushes.Transparent;
pth.Stroke = Brushes.GreenYellow;
pth.StrokeThickness = 20;
PathGeometry pg = new PathGeometry();
PathFigureCollection pfc = new PathFigureCollection();
PathFigure pf = new PathFigure();
double dim = grd.ActualHeight;
arcs = new Arc();
arcs.Center = new Point(dim / 2, dim / 2);
arcs.StartAngle = 0;
arcs.EndAngle = 0;
arcs.Radius = dim / 2;
arcs.Stroke = Brushes.YellowGreen;
arcs.StrokeThickness = 20;
arcs.SmallAngle = false;
cnv.Children.Add(arcs);
grd.Children.Insert(0, cnv);
}
答案 2 :(得分:0)
我希望这会帮助陷入困境的人们。我自己没有运气就寻找了。如果这是解决问题的方法,那么我会很高兴;)...这是一个简单的数学概念,它多次出现在...屁股上。这是代码“我们使用”:
/// <summary>
/// Defines an arc
/// </summary>
/// <seealso cref="System.Windows.Shapes.Shape" />
public class Arc : Shape
{
/// <summary>
/// Initializes the <see cref="Arc"/> class.
/// </summary>
// Angle that arc starts at
public double StartAngle
{
get => (double)GetValue(StartAngleProperty);
set => SetValue(StartAngleProperty, value);
}
// DependencyProperty - StartAngle
private static PropertyMetadata startAngleMetadata =
new FrameworkPropertyMetadata(
0.0, // Default value
FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure,
null, // Property changed callback
new CoerceValueCallback(CoerceAngle))
{
}; // Coerce value callback
public static readonly DependencyProperty StartAngleProperty =
DependencyProperty.Register("StartAngle", typeof(double), typeof(Arc), startAngleMetadata);
// Angle that arc ends at
public double EndAngle
{
get => (double)GetValue(EndAngleProperty);
set => SetValue(EndAngleProperty, value);
}
// DependencyProperty - EndAngle
private static PropertyMetadata endAngleMetadata =
new FrameworkPropertyMetadata(
90.0, // Default value
FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure,
null, // Property changed callback
new CoerceValueCallback(CoerceAngle)); // Coerce value callback
public static readonly DependencyProperty EndAngleProperty =
DependencyProperty.Register("EndAngle", typeof(double), typeof(Arc), endAngleMetadata);
/// <summary>
/// Coerces the angle.
/// </summary>
/// <param name="depObj">The dep object.</param>
/// <param name="baseVal">The base value.</param>
/// <returns></returns>
private static object CoerceAngle(DependencyObject depObj, object baseVal)
{
double angle = (double)baseVal;
angle = Math.Min(angle, 360.0);
angle = Math.Max(angle, 0.0);
return angle;
}
/// <summary>
/// Gets or sets the sweep direction.
/// </summary>
/// <value>
/// The sweep direction.
/// </value>
public SweepDirection SweepDirection
{
get => (SweepDirection)GetValue(SweepDirectionProperty);
set => SetValue(SweepDirectionProperty, value);
}
// Using a DependencyProperty as the backing store for SweepDirection. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SweepDirectionProperty =
DependencyProperty.Register("SweepDirection", typeof(SweepDirection), typeof(Arc), new FrameworkPropertyMetadata(
SweepDirection.Counterclockwise, // Default value
FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure,
null));
/// <summary>
/// Gets a value that represents the <see cref="T:System.Windows.Media.Geometry" /> of the <see cref="T:System.Windows.Shapes.Shape" />.
/// </summary>
protected override Geometry DefiningGeometry
{
get
{
var width = Visibility == Visibility.Visible ? ActualWidth : 0.0;
var height = Visibility == Visibility.Visible ? ActualHeight : 0.0;
double maxWidth = Math.Max(0.0, width - StrokeThickness);
double maxHeight = Math.Max(0.0, height - StrokeThickness);
if (maxWidth == 0
|| maxHeight == 0)
{
return new StreamGeometry();
}
var arcSize = new Size(maxWidth / 2.0, maxHeight / 2);
var calculator = new ElipticCurveCalculator(new Size(width, height), new Size(maxWidth / 2, maxHeight / 2));
var angle = EndAngle - StartAngle;
var firstAngle = Math.Min(angle, 180);
var secondAngle = Math.Max(angle - 180, 0);
// start = 20; end = 200; angle = 180
var firstStart = SweepDirection == SweepDirection.Clockwise ? -StartAngle : StartAngle;
var firstEndAngle = SweepDirection == SweepDirection.Clockwise ? firstStart - firstAngle : firstStart + firstAngle;
var secondEndAngle = 0.0;
if (secondAngle > 0)
{
secondEndAngle = SweepDirection == SweepDirection.Clockwise ? firstStart - firstAngle - secondAngle : firstStart + firstAngle + secondAngle;
}
var p1Start = calculator.GetPoint(firstStart);
var p1End = calculator.GetPoint(firstEndAngle);
StreamGeometry geom = new StreamGeometry();
using (StreamGeometryContext ctx = geom.Open())
{
ctx.BeginFigure(p1Start,
false,
false);
ctx.ArcTo(p1End,
arcSize,
0.0, // rotationAngle
false, // greater than 180 deg?
SweepDirection,
true, // isStroked
true);
if (secondEndAngle != 0)
{
var p2End = calculator.GetPoint(secondEndAngle);
ctx.ArcTo(
p2End,
arcSize,
0.0, // rotationAngle
false, // greater than 180 deg?
SweepDirection, // == SweepDirection.Clockwise ? SweepDirection.Counterclockwise : SweepDirection.Clockwise,
true, // isStroked
true);
}
}
geom.Freeze();
return geom;
}
}
private double GetFistAngle(double startAngle, double angle)
{
var endAngle = SweepDirection == SweepDirection.Counterclockwise
? Math.Min(startAngle - angle, 180)
: Math.Min(angle - startAngle, 180);
return endAngle;
}
}
/// <summary>
/// Calculates points for an eliptic curve
/// </summary>
class ElipticCurveCalculator
{
/// <summary>
/// The point calculator
/// </summary>
private readonly EllipsePointCalculator _ellipsePointCalculator;
/// <summary>
/// The half of a box size
/// </summary>
private readonly Size _boxSizeHalf;
/// <summary>
/// Initializes a new instance of the <see cref="ElipticCurveCalculator"/> class.
/// </summary>
/// <param name="boxSize">Size of the box.</param>
/// <param name="arcSize">Size of the arc.</param>
public ElipticCurveCalculator(Size boxSize, Size arcSize)
{
_ellipsePointCalculator = new EllipsePointCalculator(arcSize);
_boxSizeHalf = new Size(boxSize.Width / 2, boxSize.Height / 2);
}
/// <summary>
/// Gets the point.
/// </summary>
/// <param name="angle">The angle.</param>
/// <returns></returns>
public Point GetPoint(double angle)
{
var point = new Point(_boxSizeHalf.Width, _boxSizeHalf.Height);
var offset = _ellipsePointCalculator.GetPoint(angle);
point.Offset(offset.X, -offset.Y);
return point;
}
}
/// <summary>
/// Calculates ellipse points based on simple math
/// </summary>
public class EllipsePointCalculator
{
/// <summary>
/// Initializes a new instance of the <see cref="EllipsePointCalculator"/> class.
/// </summary>
/// <param name="size">The size of the ellipse.</param>
public EllipsePointCalculator(Size size) => Size = size;
/// <summary>
/// Gets the size.
/// </summary>
/// <value>
/// The size.
/// </value>
public Size Size { get; }
/// <summary>
/// Gets the point.
/// </summary>
/// <param name="angle">The angle.</param>
/// <returns></returns>
public Point GetPoint(double angle)
{
switch (angle)
{
case 0:
case 360:
return new Point(Size.Width, 0);
case 90:
return new Point(0, Size.Height);
case 180:
return new Point(-Size.Width, 0);
case 270:
return new Point(0, -Size.Height);
default:
break;
}
double x = Size.Width * Math.Cos(angle * Math.PI / 180.0);
double y = Size.Height * Math.Sin(angle * Math.PI / 180.0);
return new Point(x, y);
}
}`
If any can update this code to work better ;) please do so! :P