WPF自定义绘图神秘绘图错误

时间:2015-10-30 14:23:30

标签: c# wpf c#-4.0 wpf-controls custom-controls

我有一个直接绘制到自定义画布的控件。自定义控件根据物理尺寸计算绘制圆的大小。无论我使用Ellipse XAML元素还是自定义绘制控件,我所看到的行为都是相同的。

基本上,一旦元素的大小变得足够大于画布的最小尺寸,它的绘制位置就会从剪切矩形偏移。最终结果是中心点(由不同的控件绘制)是正确的,但圆圈被移动 - 并且边缘被剪裁。

示例:

Rendering Example

只要我计算的中心和实际中心对齐,控件就会正确显示。我无法找到任何明确设置剪辑的地方。

我的问题是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);

此解决方案仍存在一个问题:

  • 我的圈子仍然明显被剪掉。

2 个答案:

答案 0 :(得分:0)

这应该返回UIElement的中心:

@Override
public boolean select(final Viewer viewer, final Object parentElement, final Object element) {
    final String filterString = filterText.getText().toLowerCase();
    if (filterString.length() == 0) { return true; }

    final mydata myData= (mydata) element;
    if (filterString.matches("columnName" + ".+")) {
    index = filterString.indexOf("columnName" + ".+");
   evaluateText(myData, filterString, i, index + tableColumnsText[i].length())  
}

public boolean evaluateText(final mydata data, final String filterText, final int beginningIndex) {
        subString = filterText.substring(beginningIndex, filterText.length());
        return evaluateString(data.getString(), subString);
}


public boolean evaluateString(final String cellString, final String commaString) {
    int countSubstrings = 0;
    final String[] items = commaString.split(",");
    countSubstrings = items.length;

    for (final String s : items) {
        if (s.length() != 0) {
            if (!cellString.contains(s)) { return false; }
        }
    }
    return true;
}

答案 1 :(得分:0)

事实证明,我的定位问题的答案是,一旦孩子在任何维度上比父容器更大,DesiredSize和RenderSize之间存在差异。我必须像这样调整我的OnRender方法:

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;
    double xOffset = (DesiredSize.Width - RenderSize.Width) / 2;
    double yOffset = (DesiredSize.Width - RenderSize.Width) / 2;

    Point center = new Point(xOffset + radius, yOffset + radius);

    drawingContext.DrawEllipse(fillBrush, edgePen, center,
        radius - halfPenWidth, radius - halfPenWidth);
}

无论相对于父母的圆圈有多大,这都允许在正确的位置绘制圆圈。

我的裁剪问题是由于布局窗格有ClipToBounds=True。这完全是另一个问题。

相关问题