【发布时间】:2015-10-30 14:23:30
【问题描述】:
我有一个直接绘制到自定义画布的控件。自定义控件根据物理尺寸计算绘制圆的大小。无论我使用 Ellipse XAML 元素还是自定义绘制控件,我看到的行为都是相同的。
基本上,一旦元素的大小变得足够大到大于画布的最小尺寸,它的绘制位置就会偏离剪切矩形。最终结果是中心点(由不同的控件绘制)是正确的,但是圆被移动了——并且边缘被剪掉了。
例子:
只要我计算的中心和实际的中心对齐,控件就可以正确渲染。我找不到明确设置剪辑的任何地方。
我的问题是 2 倍:
- 发生了什么事?
-
如何才能准确地渲染到排列区域的中心?我正在使用以下方法来计算中心点:
Point center = new Point( RenderSize.Width / 2, RenderSize.Height / 2);
这在大多数情况下都有效,但当圆圈超出一定大小时则无效。
圆圈控制代码:
public class CirclePoint : UIElement
{
// field
double radius;
// additional properties
MetersPerPixel -- set by container, attached property, affects measure
RadiusInMeters -- set by application, affects measure
FillColor -- set by application, affects render
ObjectColor -- set by applicaiton, affects render
StrokeThickness -- set by application, affects measure, render
Location -- center point, set by application, affects layout
protected override Size MeasureOverride(Size constraint)
{
base.MeasureOverride(constraint);
radius = RadiusInMeters / MetersPerPixel;
double halfPenWidth = StrokThickness / 2;
double diameter = 2 * (radius + halfPenWidth);
return new Size(diameter, diameter);
}
protected override void OnRender(DrawingContext drawingContext)
{
base.OnRender(drawingContext);
SolidColorBrush fillBrush = // from FillColor, frozen
SolidColorBrush edgeBrush = // from ObjectColor, frozen
Pen edgePen = // from edgeBrush, StrokeThickness, frozen
double halfPenWidth = StrokeThickness / 2;
drawingContext.DrawEllipse(fillBrush, edgePen,
new Point(RenderSize.Width / 2, RenderSize.Height / 2),
radius - halfPenWidth, radius - halfPenWidth);
}
}
对不起,缩写符号,但我试图用相关信息总结样板代码。
自定义面板要复杂得多,因为它负责消除标签等冲突,但相关信息在这里:
public class PhysicalPane : Pane
{
// Pertinent Properties
PhysicalArea // affects layout
protected override Size MeasureOverride(Size constraint)
{
Size screen = new Screen(ActualWidth, ActualHeight);
double metersPerDisplayUnit = // calculation based on screen and other context
Size newDesiredSize = // from constraint, adjusting for double.Infinity
foreach(UIElement child in InternalChildren)
{
child.Measure(constraint);
SetMetersPerPixel(child, metersPerDisplayUnit);
newDesiredSize.Width = Math.Max(newDesiredSize.Width, child.DesiredSize.Width);
newDesiredSize.Height = Math.Max(newDesiredSize.Height, child.DesiredSize.Height);
}
return newDesiredSize;
}
protected override Size ArrangeOverride(Size finalSize)
{
foreach(UIElement child in InternalChildren)
{
Location childLocation = GetLocation(child);
// LocationToPoint is very well tested.
Point displayPoint = LocationToPoint(childLocation, PhysicalArea, finalSize);
displayPoint.X -= child.DesiredSize.Width / 2;
displayPoint.Y -= child.DesiredSize.Height / 2;
Rect locationRect = new Rect(displayPoint, child.DesiredSize);
child.Arrange(locationRect);
}
return finalSize;
}
}
原来圆圈的位置是错误的,因为 DesiredSize 和 RenderSize 不同。要修复我的 CirclePoint 中的位置,我必须像这样更改中心点逻辑:
double xOffset = (DesiredSize.Width - RenderSize.Width) / 2;
double yOffset = (DesiredSize.Width - RenderSize.Width) / 2;
Point center = new Point(xOffset + radius, yOffset + radius);
这个解决方案还有一个问题:
- 我的圈子仍然明显被剪裁。
【问题讨论】:
-
如果没有看过代码的相关部分就很难说。
-
注意:ClipToBounds 无效。 @Clemens,将尝试获得最少的代码......
-
@Clemens,添加了额外代码的相关部分。
-
到目前为止一切正常。我已经将它转储到一个测试项目中并剥离了所有缩写的东西(并在 CirclePoint 中用 MeasureCore 替换了 MeasureOverride),它按预期呈现。 “当圆圈超过一定大小时”到底是什么意思?那是什么尺寸?
-
取容器尺寸的最小尺寸,当直径大于该尺寸时,我得到错位。容器的大小无关紧要,这就是导致问题的关系。直径越大,问题越严重。
标签: c# wpf c#-4.0 wpf-controls custom-controls