【问题标题】:Wpf ArcSegment with 3 color gradient具有 3 种颜色渐变的 Wpf ArcSegment
【发布时间】:2018-10-24 12:58:29
【问题描述】:

我尝试在我的 WPF 控件中绘制一个 ArcSegment,该控件用作循环进度条并具有三色渐变。它应该以红色为 0% 开始,黄色为 50%,绿色为 100%。因此,对于 75%,它应该看起来像:

我用 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>

或者其他方向:

<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>

但问题是渐变用于整个表面,所以我用红色涂了两次而不是一次,并且在循环开始时不正确:

我尝试使用带有我想要的渐变的图片的画笔。

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

这适用于 > 75% 的值,但对于较低的值,绿色部分也会被绘制出来。

任何想法我可以做些什么来完成这项工作?

【问题讨论】:

    标签: c# wpf


    【解决方案1】:

    我让它与 ImageBrush 一起工作。最重要的是只使用图像中需要通过裁剪来绘制的部分。

    为此,我使用了一个转换器,它返回一个 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();
        }
    }
    

    我不确定这是否是最聪明的解决方案,但它执行速度很快并且实施起来并不复杂。可能其他人有更好的解决方案。

    【讨论】:

    • 嘿,我只是想做几乎相同的事情,当我遇到这个问题时,我还找到了另一个答案,可以帮助您为您提供另一种选择:here
    【解决方案2】:

    我认为使用线性渐变画笔不可能实现这种显示。

    我的解决方案是将控件分成许多小的楔形元素,每个元素都有一个纯色。每个元素的颜色是根据它的角度和控件的开始/结束角度计算的(如果你要努力创建这样一个控件,你不妨让它更通用一点)和所需的颜色停止。

    您不能只使用 Red / Green / Blue 颜色空间并为单个元素插入颜色 - 您必须改用 Hue / Saturation / Luminosity 之类的东西。

    【讨论】:

    • 我认为这实现起来可能真的很复杂,而且计算形状和颜色可能是一个非常缓慢的过程。
    • @DanielW。作为概念证明,我现在正在尝试设计这样的控件。如果我能让它以有效的方式工作,我会将结果发布在我的博客上。
    【解决方案3】:

    我意识到,这有点棘手,但如果起点在顶部、底部、左侧或右侧,则最多将 ArcSegment 分成四部分会有所帮助。 我明天可以解释更多,但棘手的部分是找到从每个 ArcSegment 的起点到终点的对角线上的梯度步骤。 如果起点在任何地方,则投影线将更难找到,因为它可能具有非直角。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-27
      • 1970-01-01
      • 1970-01-01
      • 2016-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-15
      相关资源
      最近更新 更多