Reputation: 2586
Following an example from the Book "WPF Control Development Unleashed", i modified a ProgressBar to show a circular timer instead. This contains an Arc which runs counterclockwise around the center of the window (depending on the value of my ProgressBar).
My Arc
-class inherits from System.Windows.Shapes.Shape
and I use the RenderSize.Width
and RenderSize.Height
Properties to scale it depending on my Windowsize.
This seemed to work fine at first, but the Rendersize only seems to increase. Thus my arc scales up perfectly fine when i extend the window which contains the ProgressBar, but when i size it down again the size of the arc doesn't decrease.
My ControlTemplate contains a grid in which all the elements (including the arc) are set up, so all other Elements that don't depend directly on the RenderSize (some ellipses and a textblock) scale up and down as desired.
Do you have any ideas why the RenderSize behaves like described and which values i could use instead to calculate the x/y coordinates of start/endpoints of the arc?
Remark: if i set width
and height
of the grid to a fixed value, the rendersize does not change at all which confuses me even more, since the ellipses and textbox scale accordingly to the grid already.
Upvotes: 0
Views: 2191
Reputation: 31
I had a similar issue, and (after looking at wwg2222's answer) solved it by adding the following:
protected override Size MeasureOverride(Size constraint) =>
new Size(constraint.Width, constraint.Height);
After this point, the shape sized properly and the DefiningGeometry
override had the proper RenderSize
to work with. I didn't need to override the ArrangeOverride
function.
Upvotes: 1
Reputation: 21
I also read the book "WPF Control Development Unleashed". And see the scale issue of clock control. The problem is RenderSize was not changed when the window changed its size. My solution is add some logic to ArrangeOverride and MessureOverride method.
private Size _finalSize;
protected override Size MeasureOverride(Size availableSize)
{
Debug.WriteLine(string.Format("Mesure:{0},{1}", availableSize.Width, availableSize.Height));
Size desiredSize = base.MeasureOverride(availableSize);
_finalSize = availableSize;
return desiredSize;
}
protected override Size ArrangeOverride(Size finalSize)
{
Debug.WriteLine(string.Format("Arrange:{0},{1}", _finalSize.Width, _finalSize.Height));
base.ArrangeOverride(_finalSize);
return _finalSize;
}
========================================================================= I read some materials.They said Messure and Arrange can have same logic but they should not share the data. Luckily I find another solution. First, the control should have the stretch dependency property. And then change the ArcGeometry method.
static Arc()
{
StretchProperty.OverrideMetadata(typeof(Arc), new FrameworkPropertyMetadata(Stretch.Fill));
}
private Geometry GetArcGeometry2()
{
Point startPoint = PointAtAngle(RenderSize, Math.Min(StartAngle, EndAngle));
Point endPoint = PointAtAngle(RenderSize, Math.Max(StartAngle, EndAngle));
Point stopPoint = PointAtAngle(RenderSize, Math.Max(EndAngle, 359.99));//Add this
Size arcSize = new Size(Math.Max(0, (RenderSize.Width - StrokeThickness)/2),
Math.Max(0, (RenderSize.Height - StrokeThickness)/2));
bool isLargeArc = Math.Abs(EndAngle - StartAngle) > 180;
StreamGeometry geom = new StreamGeometry();
using (StreamGeometryContext context = geom.Open())
{
context.BeginFigure(startPoint, false, false);
context.ArcTo(endPoint, arcSize, 0, isLargeArc, SweepDirection.Counterclockwise, true, false);
context.ArcTo(stopPoint, arcSize, 0, !isLargeArc, SweepDirection.Counterclockwise, false, false);//add blank arc
}
geom.Transform = new TranslateTransform(StrokeThickness/2, StrokeThickness/2);
return geom;
}
Upvotes: 2
Reputation: 367
I made a round progressbar myself, but i didn't use the RenderSize at all.
A better approach is to define an InnerRadius and OuterRadius property on your Arc and let their values be between 0 and 1.
Then, do the calculations in the Arc's DefiningGeometry override.
Since the Arc is a Shape, you can use its Stretch property to scale it up inside the controltemplate.
One issue with scaling is that the arc's bounding box varies with its value/angle. This is why you need to define an EllipseGeometry inside DefiningGeometry to fixate the boundaries of the Arc. And because of this extra Geometry I even added a second EllipseGeometry to get the filling right (because of the FillRule.EvenOdd value).
Good luck!
Upvotes: 0