4

WPF ポリラインの角の半径をカスタム値に設定することは可能ですか。WPF ボーダーの場合は可能です。私の意見では、ポリラインは StrokeLineJoin="Round" のみを設定できますが、半径は設定できません:

<Polyline Points="0,0 0,100 200,100" StrokeLineJoin="Round" />

ボーダーの場合: CornerRadius="..." が可能です:

<Border CornerRadius="8" ... />

ポリラインのカスタム コーナー丸め (線の結合点) を実現するための簡単な回避策/ハックはありますか? (たとえば、Microsoft Visio はこれを行うことができます。) ありがとうございます。

4

4 に答える 4

7

すぐに使える WPF で利用できるものを直接使用することはできません。ただし、これを行うために作成したコードを次に示します。「簡単な回避策」とは言えませんが、動作するはずです。Xaml では、次のように宣言する必要があると思います。

<myCustomControls:RoundPolyline Points="0,0 0,100 200,100" Radius="10" />

C# コード:

using System;
using System.Reflection;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;

namespace MyControls
{
    public sealed class RoundPolyline : Shape
    {
        public static readonly DependencyProperty FillRuleProperty = DependencyProperty.Register("FillRule", typeof(FillRule), typeof(RoundPolyline), new FrameworkPropertyMetadata(FillRule.EvenOdd, FrameworkPropertyMetadataOptions.AffectsRender));
        public static readonly DependencyProperty PointsProperty = DependencyProperty.Register("Points", typeof(PointCollection), typeof(RoundPolyline), new FrameworkPropertyMetadata(GetEmptyPointCollection(), FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));
        public static readonly DependencyProperty RadiusProperty = DependencyProperty.Register("Radius", typeof(double), typeof(RoundPolyline), new FrameworkPropertyMetadata(6.0, FrameworkPropertyMetadataOptions.AffectsRender));

        private Geometry _geometry;
        private void DefineGeometry()
        {
            PointCollection points = Points;
            if (points == null)
            {
                _geometry = Geometry.Empty;
                return;
            }

            PathFigure figure = new PathFigure();
            if (points.Count > 0)
            {
                // start point
                figure.StartPoint = points[0];

                if (points.Count > 1)
                {
                    // points between
                    double desiredRadius = Radius;
                    for (int i = 1; i < (points.Count - 1); i++)
                    {
                        // adjust radius if points are too close
                        Vector v1 = points[i] - points[i - 1];
                        Vector v2 = points[i + 1] - points[i];
                        double radius = Math.Min(Math.Min(v1.Length, v2.Length) / 2, desiredRadius);

                        // draw the line, and stop before the next point
                        double len = v1.Length;
                        v1.Normalize();
                        v1 *= (len - radius);
                        LineSegment line = new LineSegment(points[i - 1] + v1, true);
                        figure.Segments.Add(line);

                        // draw the arc to the next point
                        v2.Normalize();
                        v2 *= radius;
                        SweepDirection direction = (Vector.AngleBetween(v1, v2) > 0) ? SweepDirection.Clockwise : SweepDirection.Counterclockwise;
                        ArcSegment arc = new ArcSegment(points[i] + v2, new Size(radius, radius), 0, false, direction, true);
                        figure.Segments.Add(arc);
                    }

                    // last point
                    figure.Segments.Add(new LineSegment(points[points.Count - 1], true));
                }
            }
            PathGeometry geometry = new PathGeometry();
            geometry.Figures.Add(figure);
            geometry.FillRule = FillRule;
            if (geometry.Bounds == Rect.Empty)
            {
                _geometry = Geometry.Empty;
            }
            else
            {
                _geometry = geometry;
            }
        }

        protected override Size MeasureOverride(Size constraint)
        {
            DefineGeometry();
            return base.MeasureOverride(constraint);
        }

        protected override Geometry DefiningGeometry
        {
            get
            {
                return _geometry;
            }
        }

        public double Radius
        {
            get
            {
                return (double)GetValue(RadiusProperty);
            }
            set
            {
                SetValue(RadiusProperty, value);
            }
        }

        public FillRule FillRule
        {
            get
            {
                return (FillRule)GetValue(FillRuleProperty);
            }
            set
            {
                SetValue(FillRuleProperty, value);
            }
        }

        public PointCollection Points
        {
            get
            {
                return (PointCollection)GetValue(PointsProperty);
            }
            set
            {
                SetValue(PointsProperty, value);
            }
        }

        // NOTE: major hack because none of this is public, and this is very unfortunate, it should be...
        private static PointCollection _emptyPointCollection;
        private static ConstructorInfo _freezableDefaultValueFactoryCtor;
        private static object GetEmptyPointCollection()
        {
            if (_freezableDefaultValueFactoryCtor == null)
            {
                _emptyPointCollection = (PointCollection)typeof(PointCollection).GetProperty("Empty", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null, null);
                Type freezableDefaultValueFactoryType = typeof(DependencyObject).Assembly.GetType("MS.Internal.FreezableDefaultValueFactory");
                _freezableDefaultValueFactoryCtor = freezableDefaultValueFactoryType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)[0];
            }
            return _freezableDefaultValueFactoryCtor.Invoke(new object[] { _emptyPointCollection });
        }
    }     
}
于 2010-12-13T18:24:59.927 に答える
1

私が知っているわけではありませんが、ハックです...式ブレンドを使用して角の半径を設定して境界線または長方形を作成し、パスに変換しますか? これは(角の半径が設定された)長方形を取り、それをパスにします!

于 2010-09-21T12:21:01.780 に答える
0

勝利についてはhttp://www.charlespetzold.com/blog/2008/04/Rounded-Graphics-in-WPF.htmlを参照してください。

于 2010-09-21T18:49:18.927 に答える