ColorPicker Control for WPF/Silverlight
A while back I was looking around for a color picker control for Live Geometry. The ColorPicker from https://silverlightcontrib.codeplex.com was exactly what I was looking for:
(live preview needs Silverlight 3.0)
Using the control in your code
I just took the source from CodePlex and embedded it in my project. You need 5 files:
Alternatively, you can reference the binary which you can download from the SilverlightContrib CodePlex project site. Pay attention that generic.xaml contains the template for the control, so don’t forget the xaml. The control will work just fine with WPF and Silverlight, which is really a great thing, especially if you’re multitargeting.
To include the control in your application, here’s the basic code:
<sc:ColorPicker SelectedColor="LightGreen" />
Don’t forget to add an XML namespace:
xmlns:sc="clr-namespace:SilverlightContrib.Controls"
How does the gradient work?
The source code for this control is very good for educational purposes. For instance, I had no idea how they create the big gradient for every possible hue. Well, it’s genius and it’s simple. In generic.xaml:
<Canvas Canvas.Top="0" Canvas.Left="20">
<Rectangle x:Name="ColorSample" Width="180" Height="180" Fill="Red"></Rectangle>
<Rectangle x:Name="WhiteGradient" IsHitTestVisible="False" Width="180" Height="180">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Offset="0" Color="#ffffffff"/>
<GradientStop Offset="1" Color="#00ffffff"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Rectangle x:Name="BlackGradient" IsHitTestVisible="False" Width="180" Height="180">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,1" EndPoint="0, 0">
<GradientStop Offset="0" Color="#ff000000"/>
<GradientStop Offset="1" Color="#00000000"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Canvas x:Name="SampleSelector" IsHitTestVisible="False" Width="10" Height="10" Canvas.Left="100" Canvas.Top="96">
<Ellipse Width="10" Height="10" StrokeThickness="3" Stroke="#FFFFFFFF"/>
<Ellipse Width="10" Height="10" StrokeThickness="1" Stroke="#FF000000"/>
</Canvas>
</Canvas>
This canvas contains layers like in a cake. ZIndex of objects is stacked bottom to top, so the solid rectangle with initially red background is on the bottom.
Above it, there is a horizontal white gradient fill, completely white on the left and completely transparent on the right.
Above it, there is a vertical black gradient fill, completely black on the bottom and completely transparent on the top.
As these gradients overlay, the transparency over the initial solid background creates the desired effect – the actual color is in top-right, where both gradients are 100% transparent. The white spot is in top-left, where the white gradient is most intense and black gradient fades out. Same for the black edge of the gradient.
Also, it is well worth studying how the template is written – I learned a lot from this sample.
My fixes
Since I conveniently borrowed the source code for my project, I did several fixes for my own purposes. Ideally I should contribute the fixes back to SilverlightContrib, but I can never get around to it.
First of all, I reordered the two StackPanels in the template so that the actual selected color is on top. I also made it collapsible and collapsed by default. You can expand the control by clicking it like a combobox. Unlike a combobox, you have to explicitly click the color area to collapse it again.
I’ve enabled this by adding an Expanded property:
public bool Expanded
{
get
{
return m_chooserArea.Visibility == Visibility.Visible;
}
set
{
var visibility = value ? Visibility.Visible : Visibility.Collapsed;
if (m_chooserArea.Visibility == visibility)
{
return;
}
m_chooserArea.Visibility = visibility;
}
}
When clicking on the color area, I just call Enabled = !Enabled to toggle it and it does the magic for me. The default value for this is obviously the default visibility of m_chooserArea, which is specified in XAML template (Visibility=”Visible” to set to true by default).
Other fixes are not as interesting. I fixed a division by zero in ColorSpace.ConvertRgbToHsv (they had h = 60 * (g - b) / (max - min); and didn’t check if min == max). There are a couple of other things which I don’t remember off the top of my head. I’d have to view TFS history to remember what those were. If you’re willing to help and incorporate these fixes to the original project, I’ll dig this up, just let me know :)
Conclusion
Both Sara Ford and myself agree that this control deserves both thumbs up:
Comments
Anonymous
September 25, 2009
When I compile the program it prompts me an error that "The tag 'VisualStateGroup' does not exist in XML namespace 'clr-namespace:System.Windows;assembly=System.Windows'. int the ..themesgeneric.xaml"Anonymous
September 26, 2009
- Are you using Silverlight 3 / VS 2008 SP1 / Silverlight 3 Tools?
- Themes/generic.xaml should have Build Action: Page in it's Properties
- Try Clean Solution/Rebuild Solution
- In generic.xaml, make sure xmlns:sc="clr-namespace:SilverlightContrib.Controls;assembly=ColorPickerDemo" > contains the name of your assembly (ColorPickerDemo in my example) Does that help?
Anonymous
February 03, 2010
For the Expand and Collapse functionality you put in was that just on the StackPanels themselves? Hiding the lower stackpanel containing the color selection and leaving the top stackpanel? That is how I set mine up but it wants to stretch the top stackpanel to the full height of the ColorPicker... Wanted to see if you could clarify how you did it.Anonymous
February 04, 2010
The comment has been removedAnonymous
August 16, 2010
Is there a way to set the initial color as a specific RGB color?Anonymous
August 24, 2010
Paul, just set the SelectedColor propertyAnonymous
August 24, 2010
The comment has been removedAnonymous
September 24, 2012
The comment has been removed