1

I'm have try drawing color picker by Ellipse LinearGradientBrush.

<Ellipse Width="200" Height="200">
    <Ellipse.Fill>
        <VisualBrush TileMode="None">
            <VisualBrush.Visual>
                <Canvas Width="1" Height="1" SnapsToDevicePixels="True">
                    <Rectangle Width="1" Height="1" SnapsToDevicePixels="True">
                        <Rectangle.Fill>
                            <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
                                <LinearGradientBrush.GradientStops>
                                   <GradientStop Color="#FF0000" Offset="0" />
                                    <GradientStop Color="#FFFF00" Offset="0.167" />
                                    <GradientStop Color="#00FF00" Offset="0.333" />
                                    <GradientStop Color="#00FFFF" Offset="0.5" />
                                    <GradientStop Color="#0000FF" Offset="0.667" />
                                    <GradientStop Color="#FF00FF" Offset="0.833" />
                                    <GradientStop Color="#FF0000" Offset="1" />
                                </LinearGradientBrush.GradientStops>
                            </LinearGradientBrush>
                        </Rectangle.Fill>
                        <Rectangle.OpacityMask>
                            <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                                <LinearGradientBrush.GradientStops>
                                    <GradientStop Color="#FFFFFFFF" Offset="0"/>
                                    <GradientStop Color="#00FFFFFF" Offset="1"/>
                                </LinearGradientBrush.GradientStops>
                            </LinearGradientBrush>
                        </Rectangle.OpacityMask>
                    </Rectangle>
                </Canvas>
            </VisualBrush.Visual>
        </VisualBrush>
    </Ellipse.Fill>
</Ellipse>

It's just like this:

enter image description here

But How can drawing a colorpicker have multiple color and like the scattered out color like a this.

enter image description here

I have not idea. please any one help.

Mark Feldman
  • 15,731
  • 3
  • 31
  • 58
鄭宇紹
  • 15
  • 3
  • Have you considered using the [RadialGradientBrush](https://learn.microsoft.com/en-us/windows/communitytoolkit/brushes/radialgradientbrush) instead of `LinearGradientBrush`? It requires the Microsoft Community Toolkit nuget package. – Tam Bui Apr 29 '22 at 03:22
  • Yes,It's no requires nuget package.It's is in lib of media, but RadialGradientBrush how made control multi color path to path? this only control color like ring and layer by layer like a onion. – 鄭宇紹 Apr 29 '22 at 03:41
  • You're right, this package only makes color rings, and it's not what you want. I missed that part of your request, sorry for the wrong guidance. I've been searching online, and I'm not sure that anything exists for what you want, and that you would have to create the control yourself. – Tam Bui Apr 29 '22 at 04:03
  • 1
    You probably need to write a shader. https://stackoverflow.com/questions/41798927/3-colors-anglegradient-in-wpf – Jim Foye Apr 29 '22 at 22:19

1 Answers1

1

Personally, I'd just use a background texture. @Jim Foye is right though, it's very easy to do with a pixel shader:

  1. make sure you've got the fxc shader compiler installed (this tutorial should help).

  2. write a shader to convert the primitive UV coordinates to HSV, and then from HSV to RGB (math is on the HSL and HSV Wikipedia page). Here's a simple one I whipped up just now that does the job nicely:

// ColorWheelEffect.hlsl
#define PI 3.141592653f
#define value 1.0f

float4 main(float2 uv : TEXCOORD) : COLOR {
    uv = 2 * uv - 1;
    float saturation = length(uv);
    float hue = 3 * (PI - atan2(uv.y, -uv.x)) / PI;
    float chroma = value * saturation;
    float second = chroma * (1 - abs(hue % 2.0 - 1));
    float m = value - chroma;
    float3 rgb;
    if (hue < 1)
        rgb = float3(chroma, second, 0);
    else if (hue < 2)
        rgb = float3(second, chroma, 0);
    else if (hue < 3)
        rgb = float3(0, chroma, second);
    else if (hue < 4)
        rgb = float3(0, second, chroma);
    else if (hue < 5)
        rgb = float3(second, 0, chroma);
    else
        rgb = float3(chroma, 0, second);
    return float4(rgb + m, saturation < 1);
}
  1. Compile your shader into a ps file with something like this:
    fxc.exe /T ps_3_0 /E main /Fo ColorWheelEffect.ps ColorWheelEffect.hlsl
  1. Add the ps file as a resource to your WPF project and provide an effect class for it:
    public class ColorWheelEffect : ShaderEffect
    {
        public ColorWheelEffect()
        {
            this.PixelShader = new PixelShader { UriSource = new Uri("pack://application:,,,/YourApplicationName;component/ColorWheelEffect.ps", UriKind.Absolute) };
        }
    }
  1. Create an ellipse in your XAML and set the effect to an instance of your effect class:
    <!-- Must fill with transparent or you won't see anything -->
    <Ellipse Width="200" Height="200" Fill="Transparent">
        <Ellipse.Effect>
            <local:ColorWheelEffect />
        </Ellipse.Effect>
    </Ellipse>

Result:

enter image description here

Mark Feldman
  • 15,731
  • 3
  • 31
  • 58
  • 1
    Thanks your help! This may be i need, next i will trying fxc shader compiler,your answer is very nice! – 鄭宇紹 May 03 '22 at 03:26
  • @鄭宇紹 no problem. I just realized there was an unneccessary/unused shader property in the effect class, I've removed it now. Good luck! – Mark Feldman May 03 '22 at 10:59