简体   繁体   English

绘制具有不同颜色端盖的WPF线

[英]Draw a WPF Line With Different Colored End Caps

New to WPF. WPF新手。 I need to draw a line (inside a grid "cell", if that makes a difference) which has a start/end cap that is a different color than the line itself. 我需要绘制一条线(在网格“单元格”内部,如果有所不同),它的开始/结束上限与行本身颜色不同。 Seems like getting a cap on a line is easy; 似乎在线上获得上限很容易; getting it to be a different color is not so simple. 让它成为一种不同的颜色并不是那么简单。

I've reviewed the Line, PolyLine, Pen, Path, LineGeometry and EllipseGeometry objects. 我已经回顾了Line,PolyLine,Pen,Path,LineGeometry和EllipseGeometry对象。 All of these seem to offer partial solution to my problem. 所有这些似乎都为我的问题提供了部分解决方案。 This article seems to come the closest to a solution, but the code example is incomplete. 这篇文章似乎最接近解决方案,但代码示例不完整。

Happy to entertain any suggestions or solutions to my problem. 很高兴接受我的问题的任何建议或解决方案。

Here is one idea...use a linear gradient brush 这是一个想法......使用线性渐变画笔

<Window.Resources>
    <LinearGradientBrush x:Key="gb" StartPoint="0 0" EndPoint="1 0">
        <LinearGradientBrush.GradientStops>
            <GradientStop Offset="0.0" Color="Red"/>
            <GradientStop Offset="0.1" Color="Black"/>
            <GradientStop Offset="0.9" Color="Black"/>
            <GradientStop Offset="1.0" Color="Red"/>
        </LinearGradientBrush.GradientStops>
    </LinearGradientBrush>
</Window.Resources>
<Grid>
    <Line X1="100" X2="200" Y1="100" Y2="100" Stroke="{StaticResource gb}" StrokeThickness="5"/>
</Grid>

You could roll your own. 你可以自己动手。 Here is code that I found and modified to suit my needs. 这是我找到并修改以满足我的需求的代码。 I added a CapStroke and CapStrokeThickness property 我添加了CapStrokeCapStrokeThickness属性

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;

namespace LineCaps
{

    public class CappedLine: FrameworkElement
    {        
        protected override void  OnRender(DrawingContext dc)
        {
            Point pos, tangent;
            double angleInRadians;
            double angleInDegrees;
            TransformGroup tg;
            Pen pen = new Pen(Stroke, StrokeThickness);
            dc.DrawGeometry(null, pen, LinePath);

            Pen capPen = new Pen(CapStroke, CapStrokeThickness);
            if (BeginCap != null)
            {
                LinePath.GetPointAtFractionLength(0.01d, out pos, out tangent);
                angleInRadians = Math.Atan2(tangent.Y, tangent.X) + Math.PI;
                angleInDegrees = angleInRadians * 180 / Math.PI + 180;
                tg = new TransformGroup();
                tg.Children.Add(new RotateTransform(angleInDegrees));
                LinePath.GetPointAtFractionLength(0.0d, out pos, out tangent);
                tg.Children.Add(new TranslateTransform(pos.X, pos.Y));
                dc.PushTransform(tg);
                dc.DrawGeometry(CapStroke, capPen, BeginCap);
                dc.Pop();
            }
            if (EndCap != null)
            {
                LinePath.GetPointAtFractionLength(0.99, out pos, out tangent);
                angleInRadians = Math.Atan2(tangent.Y, tangent.X) + Math.PI;
                angleInDegrees = angleInRadians * 180 / Math.PI;
                tg = new TransformGroup();
                tg.Children.Add(new RotateTransform(angleInDegrees));
                LinePath.GetPointAtFractionLength(1, out pos, out tangent);
                tg.Children.Add(new TranslateTransform(pos.X, pos.Y));
                dc.PushTransform(tg);
                dc.DrawGeometry(CapStroke, capPen, EndCap);
            }         
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            //TODO: Consider creating the Pen once when Stroke and StrokeThickness are set
            return LinePath.GetRenderBounds(new Pen(Stroke, StrokeThickness)).Size;
        }

        public static readonly DependencyProperty StrokeProperty = Shape.StrokeProperty.AddOwner(typeof(CappedLine));
        public Brush Stroke
        {
            get { return (Brush)GetValue(StrokeProperty); }
            set { SetValue(StrokeProperty, value); }
        }

        public static readonly DependencyProperty StrokeThicknessProperty = Shape.StrokeThicknessProperty.AddOwner(typeof(CappedLine));
        public double StrokeThickness
        {
            get { return (double)GetValue(StrokeThicknessProperty); }
            set { SetValue(StrokeThicknessProperty, value); }
        }

        public static DependencyProperty CapStrokeProperty =
        DependencyProperty.Register(
            "CapStroke",
            typeof(Brush),
            typeof(CappedLine));
        public Brush CapStroke
        {
            get { return (Brush)GetValue(CapStrokeProperty); }
            set { SetValue(CapStrokeProperty, value); }
        }

        public static readonly DependencyProperty CapStrokeThicknessProperty =
        DependencyProperty.Register(
            "CapStrokeThickness",
            typeof(double),
            typeof(CappedLine));

        public double CapStrokeThickness
        {
            get { return (double)GetValue(CapStrokeThicknessProperty); }
            set { SetValue(StrokeThicknessProperty, value); }
        }

        public static readonly DependencyProperty LinePathProperty =
            DependencyProperty.Register("LinePath", typeof(PathGeometry), typeof(CappedLine),
            new FrameworkPropertyMetadata(
                null,
                FrameworkPropertyMetadataOptions.AffectsRender, // choose appropriate flags here!!!
                LinePathChangedCallback));
        static void LinePathChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            CappedLine me = sender as CappedLine;
            if (null != me)
            {
                me.OnLinePathChanged((PathGeometry)args.NewValue);
            }
        }
        public PathGeometry LinePath
        {
            get { return (PathGeometry)GetValue(LinePathProperty); }
            set { SetValue(LinePathProperty, value); }
        }
        public virtual void OnLinePathChanged(PathGeometry value)
        {
        }

        public static readonly DependencyProperty BeginCapProperty =
            DependencyProperty.Register("BeginCap", typeof(Geometry), typeof(CappedLine),
            new FrameworkPropertyMetadata(
                null,
                FrameworkPropertyMetadataOptions.AffectsRender, // choose appropriate flags here!!!
                BeginCapChangedCallback));
        static void BeginCapChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            CappedLine me = sender as CappedLine;
            if (null != me)
            {
                me.OnBeginCapChanged((Geometry)args.NewValue);
            }
        }
        public Geometry BeginCap
        {
            get { return (Geometry)GetValue(BeginCapProperty); }
            set { SetValue(BeginCapProperty, value); }
        }
        public virtual void OnBeginCapChanged(Geometry value)
        {
        }

        public static readonly DependencyProperty EndCapProperty =
            DependencyProperty.Register("EndCap", typeof(Geometry), typeof(CappedLine),
            new FrameworkPropertyMetadata(
                null,
                FrameworkPropertyMetadataOptions.AffectsRender, // choose appropriate flags here!!!
                EndCapChangedCallback));
        static void EndCapChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            CappedLine me = sender as CappedLine;
            if (null != me)
            {
                me.OnEndCapChanged((Geometry)args.NewValue);
            }
        }
        public Geometry EndCap
        {
            get { return (Geometry)GetValue(EndCapProperty); }
            set { SetValue(EndCapProperty, value); }
        }
        public virtual void OnEndCapChanged(Geometry value)
        {
        }
    }
}

Then to use it: 然后使用它:

<Window x:Class="LineCaps.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:loc="clr-namespace:LineCaps"
        Title="MainWindow">
    <Viewbox>
        <Canvas Height="350" Width="525">
            <loc:CappedLine BeginCap="M0,0 L6,-6 L6,6 z" EndCap="M0,-3 L0,3 L6,3 L6,-3 z" Stroke="Gold" StrokeThickness="1" CapStroke="Green" CapStrokeThickness="1" Canvas.Left="40" Canvas.Top="60">
                <loc:CappedLine.LinePath>
                    <PathGeometry Figures="M0,0 L120,120" />
                </loc:CappedLine.LinePath>
            </loc:CappedLine>

            <loc:CappedLine EndCap="M0,0 L6,-6 L6,6 z" Stroke="Blue" StrokeThickness="1" CapStroke="Red" CapStrokeThickness="1"  Canvas.Left="40" Canvas.Top="200" RenderTransformOrigin="1.5,0.5">
                <loc:CappedLine.BeginCap>
                    <EllipseGeometry Center="0,0" RadiusX="6" RadiusY="6" />
                </loc:CappedLine.BeginCap>
                <loc:CappedLine.LinePath>
                    <PathGeometry Figures="M0,0 C1,1 10.5,75.5 48.5,66.5 86.5,57.5 53.5,3.5000146 105.5,16.500091 157.5,29.500166 164.5,87.500505 164.5,87.500505" />
                </loc:CappedLine.LinePath>
                <loc:CappedLine.RenderTransform>
                    <RotateTransform Angle="0" />
                </loc:CappedLine.RenderTransform>
            </loc:CappedLine>

        </Canvas>
    </Viewbox>
</Window>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM