简体   繁体   English

Wpf ArcSegment 具有 3 种颜色渐变

[英]Wpf ArcSegment with 3 color gradient

I try to paint an ArcSegment in my WPF control that is used as an Cyclic Progress Bar and has a three color gradient.我尝试在我的 WPF 控件中绘制一个 ArcSegment,该控件用作循环进度条并具有三色渐变。 It should start with red for 0 % has yellow for 50% and green for 100%.它应该从 0% 的红色开始,50% 的黄色和 100% 的绿色。 So for 75% it should look like:所以对于 75%,它应该是这样的:

喜欢是应该看起来像

I try this with a LinearGradientBrush我用 LinearGradientBrush 试试这个

<Path StrokeThickness="25">
    <Path.Data>
        <PathGeometry>
            <PathFigure StartPoint="50, 12.5">

                <ArcSegment RotationAngle="0" SweepDirection="Clockwise"
                            IsLargeArc="true"
                            Point="12.5, 75" 
                            Size="62.5, 62.5">
                </ArcSegment>
            </PathFigure>
        </PathGeometry>
    </Path.Data>
    <Path.Stroke>
        <LinearGradientBrush StartPoint="0, 0.5" EndPoint="1, 0.5">
            <GradientStop Offset="0" Color="Green" />
            <GradientStop Offset="0.5" Color="Red" />
            <GradientStop Offset="1.0" Color="Yellow"/>
        </LinearGradientBrush>
    </Path.Stroke>
</Path>

Or in other direction:或者在其他方向:

<Path.Stroke>
    <LinearGradientBrush StartPoint="0.5, 0" EndPoint="0.5, 1">
        <GradientStop Offset="0" Color="Green" />
        <GradientStop Offset="0.5" Color="Red" />
        <GradientStop Offset="1.0" Color="Yellow"/>
    </LinearGradientBrush>
</Path.Stroke>

But the problem is that the gradient is used for the complete surface and so i have red painted two instead of one time and not correct on start of the cycle:但问题是渐变用于整个表面,所以我用红色画了两个而不是一次,并且在循环开始时不正确:

看纯色渐变

I try to use a Picture Brush with a picture having the gradient as I want it.我尝试使用带有我想要的渐变的图片的图片画笔。

<Path.Stroke>
    <ImageBrush ImageSource="../brush.png"  />
</Path.Stroke>

This works fine for values > 75% but for lower values also the green part is drawn what not should be.这适用于大于 75% 的值,但对于较低的值,绿色部分也会绘制不应该是什么。

在此处输入图片说明

Any idear what I can do to make this work?任何想法我能做些什么来使这项工作?

I get it working with an ImageBrush.我让它与 ImageBrush 一起工作。 The ting is to use only the part of the image that is needed to be painted by cropping it. ting 是仅使用需要通过裁剪来绘制的图像部分。

To do so I used a Converter that returns a ImageBrush vor the current percentage value.为此,我使用了一个 Converter,它返回一个 ImageBrush 或当前百分比值。

public class ValueToImageBrush : IValueConverter
{
    private const string _filePath = "pack://application:,,,/XXX;component/brush.png";
    private BitmapImage _baseImage;

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var doubleValue = value as double?;
        if (doubleValue == null) return new SolidColorBrush(Colors.LightSlateGray);

        var baseImg = LoadImage();           
        var img = CutImage(baseImg, doubleValue.Value);

        return InitImageBrush(img);
    }       


    private BitmapImage LoadImage()
    {
        if (_baseImage == null)
        {
            _baseImage = new BitmapImage();
            _baseImage.BeginInit();
            _baseImage.UriSource = new Uri(_filePath);
            _baseImage.EndInit();
        }
        return _baseImage;
    }

    private static ImageSource CutImage(BitmapImage baseImg, double doubleValue)
    {
        var img = baseImg as ImageSource;
        if (doubleValue < 50)
        {
            var usedHight = Math.Max(25.0, baseImg.PixelHeight * (doubleValue * 2 / 100));
            img = new CroppedBitmap(baseImg,
                new Int32Rect(baseImg.PixelWidth / 2, 0, baseImg.PixelWidth / 2, (int)usedHight));
        }
        else if (doubleValue < 75)
        {
            var usedWidth = baseImg.PixelWidth * (doubleValue / 100);
            img = new CroppedBitmap(baseImg, new Int32Rect(200 - (int)usedWidth, 0, (int)usedWidth, baseImg.PixelHeight));
        }

        return img;
    }
    private static object InitImageBrush(ImageSource img)
    {
        ImageBrush imgBrush = new ImageBrush();
        imgBrush.ImageSource = img;
        imgBrush.Stretch = Stretch.None;
        return imgBrush;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

I'm not sure if this is the smartest solution but it performs fast and was not really complex to be implemented.我不确定这是否是最聪明的解决方案,但它执行速度很快,而且实施起来并不复杂。 May be someone else has a better solution.可能其他人有更好的解决方案。

I don't think this sort of display is possible using a linear gradient brush.我认为使用线性渐变画笔不可能实现这种显示。

My solution would be to divide the control up into a number of small wedge-shaped elements, each of which has a single solid colour.我的解决方案是将控件分成许多小的楔形元素,每个元素都有单一的纯色。 The colour for each element is calculated based on its angle and the start / end angle of the control (if you're going to make the effort to create such a control, you might as well make it a little more generic) and the required colour stops.每个元素的颜色是根据它的角度和控件的开始/结束角度计算的(如果你要努力创建这样一个控件,你最好让它更通用一点)和所需的颜色停止。

You can't just use the Red / Green / Blue colour space and interpolate the colour for an individual element though - you'd have to use something like Hue / Saturation / Luminosity instead.您不能只使用红色/绿色/蓝色颜色空间并为单个元素插入颜色 - 您必须使用色相/饱和度/亮度之类的东西。

I realized, it's a little tricky, but deviding the ArcSegment in four pieces at most would help, if the starting point is right at the top, bottom, left or right.我意识到,这有点棘手,但如果起点位于顶部、底部、左侧或右侧,则最多将 ArcSegment 分成四部分会有所帮助。 I can explain more tomorrow, but the tricky part was to find the gradient steps prjocted on a diagonal line from starting point to end point of each ArcSegment.我明天可以解释更多,但棘手的部分是找到从每个 ArcSegment 的起点到终点的对角线上的梯度步骤。 If the starting point was anywhere, the projection line would be harder to find as it may have non rectangular angles.如果起点在任何地方,投影线将更难找到,因为它可能具有非矩形角度。

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

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