Click here to Skip to main content
Click here to Skip to main content

WPF ColorPicker and BrushEditor

By , 25 Jun 2012
Rate this:
Please Sign up or sign in to vote.

Introduction 

Well, I still hadn't found the perfect WPF ColorPicker Control to use in my projects. There are some nice ones out there, but my favourite is KAXAML's, so, I thought I might try to replicate it.  

Background  

The project is loosely MVVM and contains two UserControls, ColorEditor and BrushEditor and are packaged in a separate class library project for your convenience.  

The first hurdle I had was trying to generate the ColorPicker swatch. WriteableBitmap was terribly slow, so I decided to cache the 100 Hue swatches (being 0 - 1 with increments of 1%). Generating the Bitmaps was made much easier (having never had an occasion to use them) with the SimpleBitmap class found in the Community Content section of WriteableBitmap (http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.writeablebitmap.aspx)  

The next hurdle for me was retemplating the Sliders for Hue and Alpha, again, something I hadn't done before. I mucked about with a couple of ControlTemplates before taking KAXAML's own Simple Styles style and bending it to my will. The Hue Slider background is simply a Border with a LinearGradientBrush and 7 GradientStops.  

The Alpha Slider and selected color box were somewhat tricky too, and I must profess to not fully understanding why the DrawingBrush that displays the checker pattern works.  

However, I think the trickiest part of this, to my surprise, was actually the RGBA/HSLA TextBox's! Basically, the problem is this. If you update say, the R value, you must also update H, S and L. If you update H, you must update R, if you update S, you must update R. This mightn't be so bad except that the conversion code from RGB to HSL isn't perfect. Ie, HSL (0.56, .60, .23) might not align perfectly to an RGB value.  So, it rounds the RGB value. But perhaps that rounding alters the H value just a tiny bit. So we alter the RGB values, which skew the H just a tiny bit. In the end, I simply said, if you change the H value, set a flag, update the RGB values, when they attempt to update the HSL values, check if that flag is set. If so, don't update. Simple in retrospect of course. 

Using the code   

The editors are used just like any other UserControl.

<Window 
    x:Class="BrushEditor.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:ColorEditor="clr-namespace:Lovatts.ColorEditor;assembly=Lovatts.ColorEditor" 
    Title="MainWindow" 
    Height="350" 
    Width="525">

  <ColorEditor:BrushEditor></ColorEditor:BrushEditor>
</Window>

But you can also bind to/use the underlying ViewModels: 

ColorEditor colorEditor = new ColorEditor();
colorEditor.ColorEditorViewModel.Color = Colors.Blue;
colorEditor.ColorEditorViewModel.RGB.A = 67;
Lovatts.ColorEditor.BrushEditor brushEditor = new Lovatts.ColorEditor.BrushEditor();
brushEditor.BrushEditorViewModel.BrushType = BrushTypes.Radial;
brushEditor.BrushEditorViewModel.Center = new Point(1, 0);
brushEditor.BrushEditorViewModel.GradientStops.Clear();   
brushEditor.BrushEditorViewModel.GradientStops.Add(new GradientStopViewModel(Colors.Blue, 1);  
brushEditor.BrushEditorViewModel.GradientStops.Add(new GradientStopViewModel(Colors.Red, 0));

Brush serialization/deserialization methods are included for convenience. 

string xml = brushEditor.BrushEditorViewModel.SerializeBrushToXml();
brushEditor.BrushEditorViewModel.DeserializeBrushFromXml(xml);

The XML output being...

<RadialGradientBrush
  Center="1,0" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
  <RadialGradientBrush.GradientStops>   
    <GradientStop
      Color="#FFFF0000"
      Offset="0" />
    <GradientStop
      Color="#FF0000FF"
      Offset="1" />
  </RadialGradientBrush.GradientStops>
</RadialGradientBrush>

Points of Interest

Well.. this is my first ever CodeProject submission and took about a day to write. 

There's a slight issue when changing the hue slider, in that it will sometimes snap the palette thumb to an RGB value.  

The hex code TextBox is automatically set to OverType (using the method below) which I find much more user friendly:  

private void MakeHexTextBoxOverType()
{
    PropertyInfo textEditorProperty = typeof (TextBox).GetProperty(
       "TextEditor", BindingFlags.NonPublic | BindingFlags.Instance);
    object textEditor = textEditorProperty.GetValue(hexTextBox, null);
    // set _OvertypeMode on the TextEditor
    PropertyInfo overtypeModeProperty = textEditor.GetType().GetProperty(
       "_OvertypeMode", BindingFlags.NonPublic | BindingFlags.Instance);
    overtypeModeProperty.SetValue(textEditor, true, null);
} 

History 

  • 19/6/2012: Posted article.
  • 20/6/2012: Uploaded source 
  • 26/6/2012: Updated Background 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Matthew Searles
Software Developer Lovatts Publications
Australia Australia
No Biography provided

Comments and Discussions

 
GeneralMy vote of 5 PinmemberS.A.Esmaeily14-Aug-13 0:35 
GeneralMy vote of 5 PinmemberJaikrishan11-Mar-13 0:13 
GeneralRe: My vote of 5 PinmemberMatthew Searles14-Apr-13 19:13 
QuestionSuggestion : Add some screenshot Pinmemberamitgajjar19-Jun-12 20:29 
AnswerRe: Suggestion : Add some screenshot PinmemberMatthew Searles20-Jun-12 14:02 
GeneralRe: Suggestion : Add some screenshot PinmemberMatthew Searles20-Jun-12 14:16 
QuestionNice pickers there PinmvpSacha Barber19-Jun-12 1:55 
GeneralRe: Nice pickers there PinmemberMatthew Searles19-Jun-12 20:17 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140415.2 | Last Updated 26 Jun 2012
Article Copyright 2012 by Matthew Searles
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid