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

WPF: A Simple Color Picker With Preview

By , 17 Apr 2012
 

Contents

Introduction

Yesterday, I posted an article about creating a WPF Graph, and when I post a new article, I always have a look at the new articles, including those awaiting public status. Yesterday, someone published a WPF color picker that looked really cool. The only problem was the code was not attached to that article and the article text gave you no clue as to how the damn thing worked. I joked to a fellow CodeProject author that I just may have to try and write a color picker for WPF, as this article sparked my interest a bit.

As luck would have it, I woke up today (Monday) and tried to get into work (I work in London and live 50 miles away), but was faced with the worst snow storm in the UK for some time. No trains/buses/taxis were on, so guess what I did? That's right, I wrote a color picker.

This article is it.

It is very simple actually. I should point out before I start that I did borrow an idea or two from other excellent sources from the www. So I would like to start by having a special thanks section.

Special Thanks Goes Out To

The Code

So how does it all work? Well, it is actually so simple you probably would think "Ha, is that it". Well yep, this next section explains all that is involved, which ain't that much. Simplicity is good.

There is a WPF Window called ColorDialog which holds the actual ColorPicker control. Here is the XAML:

<Window x:Class="WPFColorPickerLib.ColorDialog"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="clr-namespace:WPFColorPickerLib"
      Icon="Images/ColorSwatchSquare.png"
      Title="Pick Color" Height="370" 
      KeyDown="Window_KeyDown"
      Width="520" 
      WindowStartupLocation="CenterOwner">
    <local:ColorPicker x:Name="colorPicker"/>
</Window>

This ColorDialog window is the one you can use from your own code. The ColorDialog window exposes a single property which is really just the value of the currently selected color within the contained ColorPicker control.

Here is the code-behind for the ColorDialog window:

public partial class ColorDialog : Window
{
    #region Ctor
    public ColorDialog()
    {
        InitializeComponent();
    }
    #endregion

    #region Public Properties
    public Color SelectedColor
    {
        get { return colorPicker.SelectedColor; }
    }
    #endregion

    #region Private Methods
    /// <summary>
    /// Closes the dialog on Enter key pressed
    /// </summary>
    private void Window_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Enter)
        {
            this.Close();
        }
    }

    /// <summary>
    /// User is happy with choice
    /// </summary>
    private void btnOk_Click(object sender, RoutedEventArgs e)
    {
        DialogResult = true;
    }

    /// <summary>
    /// User is not happy with choice
    /// </summary>
    private void btnCancel_Click(object sender, RoutedEventArgs e)
    {
        DialogResult = false;
    }
    #endregion
}

And here is how you could use it from your own WPF code to set a Color:

private void btnPickColor_Click(object sender, RoutedEventArgs e)
{
    ColorDialog colorDialog = new ColorDialog();
    colorDialog.Owner = this;
    if ((bool)colorDialog.ShowDialog())
    {
        RectColorPicked.Fill = new SolidColorBrush(colorDialog.SelectedColor);
    }
}

The actual ColorPicker control works as follows:

There are a number of static swatch images:

that the user may pick from, using the image buttons provided at the top of the ColorPicker control. The user is then able to use the mouse to move around the image, and also adjust the Alpha value using the slider. The SelectedColor is worked out based on where the mouse is in relationship to the current static swatch image. Basically, a single pixel under the mouse is retrieved from the current static swatch image, and this is made into a 1*1 byte array, and then the values within this 1*1 byte array are used to create a Color, taking into account the current Alpha slider value.

The following diagram may help to explain it a little better.

One of the nice things about this control is the Preview, which is simply using a WPF InkPresenter control and showing some strokes on it. And the nice checker background is easily achieved in WPF using a DrawingBrush.

In essence, that is how it works, so probably time for some code.

Here is the entire XAML for the ColorPicker control:

<UserControl x:Class="WPFColorPickerLib.ColorPicker"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      Height="340" Width="510">
    <UserControl.Resources>
        <DrawingBrush x:Key="CheckerboardBrush" 
        Stretch="None" TileMode="Tile" 
                 AlignmentX="Left" AlignmentY="Top" 
                 Viewport="0,0,10,10" ViewportUnits="Absolute">
            <DrawingBrush.Drawing>
                <DrawingGroup>
                    <GeometryDrawing Brush="sc# 1,1,1">
                        <GeometryDrawing.Geometry>
                            <RectangleGeometry Rect="0,0,10,10" />
                        </GeometryDrawing.Geometry>
                    </GeometryDrawing>
                    <GeometryDrawing Brush="sc# 0.5,0.5,0.5">
                        <GeometryDrawing.Geometry>
                            <RectangleGeometry Rect="0,0,5,5" />
                        </GeometryDrawing.Geometry>
                    </GeometryDrawing>
                    <GeometryDrawing Brush="sc# 0.5,0.5,0.5">
                        <GeometryDrawing.Geometry>
                            <RectangleGeometry Rect="5,5,5,5" />
                        </GeometryDrawing.Geometry>
                    </GeometryDrawing>
                </DrawingGroup>
            </DrawingBrush.Drawing>
        </DrawingBrush>
    </UserControl.Resources>

    <Grid Background="White">

        <Grid.RowDefinitions>
            <RowDefinition Height="35"/>
            <RowDefinition Height="230"/>
            <RowDefinition Height="70"/>
        </Grid.RowDefinitions>

        <StackPanel Grid.Row="0" Height="35" 
                    HorizontalAlignment="Stretch"
                    Orientation="Horizontal" 
                    Background="Black">
            <Label Content="Pick swatch type" 
                   Foreground="White" FontWeight="Bold" 
                   VerticalAlignment="Center"/>
            <Image x:Name="ImgSqaure1" 
                   Height="20" Width="20" 
                   Source="Images/ColorSwatchSquare.png" 
                   Margin="45,0,0,0" 
                   ToolTip="Square swatch1" 
                   MouseLeftButtonDown="Swatch_MouseLeftButtonDown"/>
            <Image x:Name="ImgSqaure2" 
                   Height="20" Width="20" 
                   Source="Images/ColorSwatchSquare2.png" Margin="5,0,0,0" 
                   ToolTip="Square swatch2" 
                   MouseLeftButtonDown="Swatch_MouseLeftButtonDown"/>
            <Image x:Name="ImgCircle1" Height="20" Width="20" 
                   Source="Images/ColorSwatchCircle.png" Margin="5,0,0,0" 
                   ToolTip="Circle swatch1" 
                   MouseLeftButtonDown="Swatch_MouseLeftButtonDown"/>
        </StackPanel>

        <Grid Grid.Row="1" Height="230" 
                       VerticalAlignment="Top">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="170"/>
                <ColumnDefinition Width="170"/>
                <ColumnDefinition Width="170"/>
            </Grid.ColumnDefinitions>

            <!-- Colorbox, Column1-->
            <Grid Grid.Column="0" 
                     Grid.Row="0" Margin="10,30,0,0" >

                <Border BorderBrush="Black" BorderThickness="2" 
                    HorizontalAlignment="Center" 
                    VerticalAlignment="Top"
                    Background="White"
                    Width="154" Height="154">
                </Border>
              
                
                
                <Image x:Name="ColorImage" 
                       Width="150" Height="150" 
                       HorizontalAlignment="Center"
                       VerticalAlignment="Top" Margin="2"
                       Source="Images/ColorSwatchSquare.png"/>

                <Canvas x:Name="CanvImage" 
                       Width="150" Height="150" 
                       HorizontalAlignment="Center"
                       Background="Transparent"
                       VerticalAlignment="Top" Margin="2"
                       MouseDown="CanvImage_MouseDown"
                       MouseUp="CanvImage_MouseUp"
                       MouseMove="CanvImage_MouseMove">
                    <Ellipse x:Name="ellipsePixel" Width="10" 
                       Height="10" Stroke="Black" Fill="White" 
                       Canvas.Left="0" Canvas.Top="0"/> 
                    
                </Canvas>


            </Grid>

            <!-- Preview, Column1-->
            <StackPanel Grid.Column="1" Orientation="Vertical" >
                <Label Content="Preview" Margin="5,0,0,0" 
                     HorizontalAlignment="Left" 
                     Foreground="Black" FontWeight="Bold" 
                     VerticalAlignment="Center"/>

                <Border Margin="4,5,10,0" Width="154" 
                        Height="154" 
                        HorizontalAlignment="Left" 
                        BorderBrush="Black" BorderThickness="2"
                        Background="{StaticResource CheckerboardBrush}">
                    <InkPresenter Name="previewPresenter" 
                        Margin="0" Width="150" Height="150"
                        Strokes="AOcBAxdIEESAgYAERYQBGwIAJAFGhAEbAgAk
                         AQUBOBkgMgkA9P8CAekiOkUzCQD4nwIBWiA6RTgIAP4DAAAAg
                         H8RAACAPx8JEQAAAAAAAPA/CpYBNIfm3uajgcQgUUiUkjUelE
                         al0KkUBh0HichlM1mtJotZp9JodDl8jk8ZgcBiUOjUYl08
                         m0+l0+lFCjksjESAh+kg6auNwaEwSBQiEQyLRKTRiVSiUSSORy
                         LQ6JQSBIPFYnKZTL5fOZfMZXL4/H47DYLBYHFoJLIpEo9GgIP3OB5
                         PlxLCJiZmU1MISSi4SJiS74+D4+4o" />
                </Border>

            </StackPanel>

            <!-- TextBoxes, Column2-->
            <StackPanel Grid.Column="2" Orientation="Vertical" >

                <StackPanel Orientation="Horizontal" Margin="0,30,0,0">
                    <Label Content="A" Margin="5,0,0,0" 
                            HorizontalAlignment="Left" 
                            Foreground="Black" FontWeight="Bold" 
                            VerticalAlignment="Center"/>
                    <Border CornerRadius="5" 
                            BorderBrush="Black" Background="LightGray" 
                            BorderThickness="2" 
                            Width="50" Height="30">
                        <TextBox x:Name="txtAlpha" 
                            BorderThickness="0" Background="LightGray" 
                            BorderBrush="Transparent" 
                            Margin="5,1,5,1" IsReadOnly="True"/>
                    </Border>
                    <Border CornerRadius="5" 
                            BorderBrush="Black" Background="LightGray" 
                            BorderThickness="2" Margin="10,0,0,0" 
                            Width="50" Height="30">
                        <TextBox x:Name="txtAlphaHex" BorderThickness="0" 
                            Background="LightGray" BorderBrush="Transparent"
                            Margin="5,1,5,1" IsReadOnly="True"/>
                    </Border>
                </StackPanel>

                <StackPanel Orientation="Horizontal" Margin="0,5,0,0">
                    <Label Content="R" Margin="5,0,0,0" 
                            HorizontalAlignment="Left" 
                            Foreground="Black" FontWeight="Bold" 
                            VerticalAlignment="Center"/>
                    <Border CornerRadius="5" BorderBrush="Black" 
                            Background="LightGray" 
                            BorderThickness="2" Width="50" 
                            Height="30">
                        <TextBox x:Name="txtRed" 
                            BorderThickness="0" Background="LightGray" 
                            BorderBrush="Transparent" 
                            Margin="5,1,5,1" IsReadOnly="True"/>
                    </Border>
                    <Border CornerRadius="5" 
                            BorderBrush="Black" Background="LightGray" 
                            BorderThickness="2" Margin="10,0,0,0" 
                            Width="50" Height="30">
                        <TextBox x:Name="txtRedHex" 
                            BorderThickness="0" Background="LightGray" 
                            BorderBrush="Transparent" 
                            Margin="5,1,5,1" IsReadOnly="True"/>
                    </Border>
                </StackPanel>

                <StackPanel Orientation="Horizontal" Margin="0,5,0,0">
                    <Label Content="G" Margin="5,0,0,0" 
                            HorizontalAlignment="Left" 
                            Foreground="Black" FontWeight="Bold" 
                            VerticalAlignment="Center"/>
                    <Border CornerRadius="5" 
                            BorderBrush="Black" Background="LightGray" 
                            BorderThickness="2" Width="50" Height="30">
                        <TextBox x:Name="txtGreen" BorderThickness="0" 
                            Background="LightGray" BorderBrush="Transparent" 
                            Margin="5,1,5,1" IsReadOnly="True"/>
                    </Border>
                    <Border CornerRadius="5" 
                            BorderBrush="Black" Background="LightGray"
                            BorderThickness="2" Margin="10,0,0,0" 
                            Width="50" Height="30">
                        <TextBox x:Name="txtGreenHex" BorderThickness="0"
                            Background="LightGray" BorderBrush="Transparent" 
                            Margin="5,1,5,1" IsReadOnly="True"/>
                    </Border>
                </StackPanel>

                <StackPanel Orientation="Horizontal" Margin="0,5,0,0">
                    <Label Content="B" Margin="5,0,0,0" 
                           HorizontalAlignment="Left" 
                           Foreground="Black" FontWeight="Bold" 
                           VerticalAlignment="Center"/>
                    <Border CornerRadius="5" BorderBrush="Black" 
                           Background="LightGray" 
                           BorderThickness="2" Width="50" Height="30">
                        <TextBox x:Name="txtBlue" 
                           BorderThickness="0" Background="LightGray" 
                           BorderBrush="Transparent" 
                           Margin="5,1,5,1" IsReadOnly="True"/>
                    </Border>
                    <Border CornerRadius="5" BorderBrush="Black" 
                            Background="LightGray" 
                            BorderThickness="2" Margin="10,0,0,0" 
                            Width="50" Height="30">
                        <TextBox x:Name="txtBlueHex" BorderThickness="0" 
                            Background="LightGray" BorderBrush="Transparent" 
                            Margin="5,1,5,1" IsReadOnly="True"/>
                    </Border>
                </StackPanel>

                <StackPanel Orientation="Horizontal" Margin="0,5,0,0">
                    <Border CornerRadius="5" Margin="22,0,0,0" 
                            Background="LightGray" 
                            BorderBrush="Black" BorderThickness="2" 
                            Width="112" Height="30">
                        <TextBox x:Name="txtAll"
                            BorderThickness="0" Background="LightGray" 
                            BorderBrush="Transparent" 
                            Margin="5,1,5,1" IsReadOnly="True"/>
                    </Border>
                </StackPanel>
                
            </StackPanel>
            
        </Grid>

        <!--AlphaSlider-->
        <Border x:Name="AlphaBorder" Grid.Row="2" Grid.ColumnSpan="2" 
                BorderBrush="Black" Height="60"
                BorderThickness="2" CornerRadius="5" Margin="10,5,10,5">
            <Slider x:Name="AlphaSlider" Orientation="Horizontal" 
                Minimum="0" Maximum="255" 
                SmallChange="1" LargeChange="25"
                VerticalAlignment="Center" Margin="5" 
                Value="255"
                ValueChanged="AlphaSlider_ValueChanged"/>
        </Border>
    </Grid>
</UserControl>

And here is all the C# code-behind for the ColorPicker control:

public partial class ColorPicker : UserControl
{
    #region Data
    private DrawingAttributes drawingAttributes = new DrawingAttributes();
    private Color selectedColor = Colors.Transparent;
    private Boolean IsMouseDown = false;
    #endregion

    #region Ctor
    public ColorPicker()
    {
        InitializeComponent();
        this.Loaded += new RoutedEventHandler(ColorPicker_Loaded);
    }
    #endregion

    #region Public Properties
    /// <summary>
    /// gets or privately sets the selected
    /// Color. When the Color is set 
    /// the CreateAlphaLinearBrush()/UpdateTextBoxes()
    /// and UpdateInk() methods are called
    /// </summary>
    public Color SelectedColor
    {
        get { return selectedColor; }
        private set
        {
            if (selectedColor != value)
            {
                selectedColor = value;
                CreateAlphaLinearBrush();
                UpdateTextBoxes();
                UpdateInk();
            }
        }
    }
    #endregion

    #region Private Methods
    /// <summary>
    /// Start with a default Color of black
    /// </summary>
    private void ColorPicker_Loaded(object sender, RoutedEventArgs e)
    {
        SelectedColor = Colors.Black;
    }

    /// <summary>
    /// Creates a new LinearGradientBrush background for the
    /// Alpha area slider. This is based on the current color
    /// </summary>
    private void CreateAlphaLinearBrush()
    {
        Color startColor = Color.FromArgb(
                (byte)0,
                SelectedColor.R, 
                SelectedColor.G, 
                SelectedColor.B);

        Color endColor = Color.FromArgb(
                (byte)255,
                SelectedColor.R, 
                SelectedColor.G, 
                SelectedColor.B);

        LinearGradientBrush alphaBrush = 
            new LinearGradientBrush(startColor, endColor, 
                new Point(0, 0), new Point(1, 0));

        AlphaBorder.Background = alphaBrush;
    }


    /// <summary>
    /// apply the new Swatch image based on user requested swatch
    /// </summary>
    private void Swatch_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        Image img = (sender as Image);
        ColorImage.Source = img.Source;
    }


    /// <summary>
    /// Simply grab a 1*1 pixel from the current color image, and
    /// use that and copy the new 1*1 image pixels to a byte array and
    /// then construct a Color from that.
    /// </summary>
    private void CanvImage_MouseMove(object sender, MouseEventArgs e)
    {
        if (!IsMouseDown)
            return;

        try
        {
            CroppedBitmap cb = new CroppedBitmap(ColorImage.Source as BitmapSource,
                new Int32Rect((int)Mouse.GetPosition(CanvImage).X,
                    (int)Mouse.GetPosition(CanvImage).Y, 1, 1));

            byte[] pixels = new byte[4];

            try
            {
                cb.CopyPixels(pixels, 4, 0);
            }
            catch (Exception ex)
            {
                //Ooops
            }

            //Ok now, so update the mouse cursor position and the SelectedColor
            ellipsePixel.SetValue(Canvas.LeftProperty,
                                 (double)(Mouse.GetPosition(CanvImage).X-5));
            ellipsePixel.SetValue(Canvas.TopProperty, 
                                 (double)(Mouse.GetPosition(CanvImage).Y-5));
            CanvImage.InvalidateVisual();
            SelectedColor = Color.FromArgb((byte)AlphaSlider.Value, 
                                            pixels[2], pixels[1], pixels[0]);
        }
        catch (Exception exc)
        {
            //not much we can do
        }
    }

    /// <summary>
    /// Update text box values based on SelectedColor
    /// </summary>
    private void UpdateTextBoxes()
    {
        txtAlpha.Text = SelectedColor.A.ToString();
        txtAlphaHex.Text = SelectedColor.A.ToString("X");
        txtRed.Text = SelectedColor.R.ToString();
        txtRedHex.Text = SelectedColor.R.ToString("X");
        txtGreen.Text = SelectedColor.G.ToString();
        txtGreenHex.Text = SelectedColor.G.ToString("X");
        txtBlue.Text = SelectedColor.B.ToString();
        txtBlueHex.Text = SelectedColor.B.ToString("X");
        txtAll.Text = String.Format("#{0}{1}{2}{3}",
                txtAlphaHex.Text, txtRedHex.Text, 
                txtGreenHex.Text, txtBlueHex.Text);
    }

    /// <summary>
    /// Updates Ink stroked based on SelectedColor
    /// </summary>
    private void UpdateInk()
    {
        drawingAttributes.Color = SelectedColor;
        drawingAttributes.StylusTip = StylusTip.Ellipse;
        drawingAttributes.Width = 5;

        // Update DA on previewPresenter
        foreach (Stroke s in previewPresenter.Strokes)
        {
            s.DrawingAttributes = drawingAttributes;
        }
    }

    /// <summary>
    /// Update SelectedColor Aplha based on Slider value
    /// </summary>
    private void AlphaSlider_ValueChanged(object sender, 
        RoutedPropertyChangedEventArgs<double> e)
    {
        SelectedColor = 
            Color.FromArgb(
                (byte)AlphaSlider.Value,
                SelectedColor.R, 
                SelectedColor.G, 
                SelectedColor.B);
    }

    /// <summary>
    /// Change IsMouseDown state
    /// </summary>
    private void CanvImage_MouseDown(object sender, MouseButtonEventArgs e)
    {
        IsMouseDown = true;
    }

    /// <summary>
    /// Change IsMouseDown state
    /// </summary>
    private void CanvImage_MouseUp(object sender, MouseButtonEventArgs e)
    {
        IsMouseDown = false;
    }
    #endregion
}

So What Do You Think?

I would just like to ask, if you liked the article, please vote for it, and leave some comments, as it lets me know if the article was at the right level or not, and whether it contained what people need to know.

More News

One of the readers of this article, a one Mark Treadwell, has taken this idea further and enhanced this dialog to allow the dialog to also show a selected Color on ShowDialog(), and also done various other enhancements. You can read more about this over at Mark's blog post at http://geekswithblogs.net/mtreadwell/archive/2010/01/03/137314.aspx, and here is a link to his source code: Marc's better ColorPicker.

A few people have asked for this, but I have been too busy, so thanks Marc.

License

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

About the Author

Sacha Barber
Software Developer (Senior)
United Kingdom United Kingdom
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)
 
- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence
 
Both of these at Sussex University UK.
 
Award(s)

I am lucky enough to have won a few awards for Zany Crazy code articles over the years

  • Microsoft C# MVP 2013
  • Codeproject MVP 2013
  • Microsoft C# MVP 2012
  • Codeproject MVP 2012
  • Microsoft C# MVP 2011
  • Codeproject MVP 2011
  • Microsoft C# MVP 2010
  • Codeproject MVP 2010
  • Microsoft C# MVP 2009
  • Codeproject MVP 2009
  • Microsoft C# MVP 2008
  • Codeproject MVP 2008
  • And numerous codeproject awards which you can see over at my blog

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionVery nice SachamemberMike Hankey18-Apr-12 1:31 
When are you going to reach God status in Author category? Smile | :)
VS2010/Atmel Studio 6.0 ToDo Manager Extension
Version 3.0 now available.
There is no place like 127.0.0.1

AnswerRe: Very nice SachamvpSacha Barber18-Apr-12 2:23 
Thanks glad you like it, its an old one, I just did small update is all
Sacha Barber
  • Microsoft Visual C# MVP 2008-2012
  • Codeproject MVP 2008-2012
Open Source Projects
Cinch SL/WPF MVVM

Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

QuestionChanging form backroundmemberkumika16-Jan-12 8:59 
This is good stuff. However the slider does not work when you set form background. You get a dark colour. Why is that? Thanks
Questionreally nicememberCIDev13-Dec-11 6:28 
For some reason I have always liked Color Pickers and this is a really nice one and the article is well written.
Just because the code works, it doesn't mean that it is good code.

AnswerRe: really nicemvpSacha Barber13-Dec-11 20:19 
Make sure you grab Mark Treadwells one, he did a load of enhancements.
 
http://www.narboza.com/files/WPFColorPicker.zip
Sacha Barber
  • Microsoft Visual C# MVP 2008-2011
  • Codeproject MVP 2008-2011
Open Source Projects
Cinch SL/WPF MVVM

Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

QuestionLicensememberHabufe24-Jul-11 23:03 
Hello Sacha,
 
I have recently found this wonderful control and wanted to use it in a free application I am developing, however the license you chose (CPOL) is relatively restrictive in terms of what I am trying to do. Is it possible that you release it under a more permissive license such as GPL, MIT or even LGPL?
 
Regards,
Habufe
AnswerRe: LicensemvpSacha Barber24-Jul-11 23:09 
Ah its just the codeproject license, as far as I am concerned do what you like with it, use it however you want
 

Make sure you check near the end of the article there is a couple of enhancements and there is a link to a chaps web site where he took this code and made it better.
 
This is the link : http://geekswithblogs.net/mtreadwell/archive/2010/01/03/137314.aspx
Sacha Barber
  • Microsoft Visual C# MVP 2008-2011
  • Codeproject MVP 2008-2011
Open Source Projects
Cinch SL/WPF MVVM

Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

GeneralRe: LicensememberHabufe24-Jul-11 23:41 
Hello Sacha,
 
Firstly, thanks for linking me to the updated version.
The CPOL license is very restrictive. It requires, for every modification done to the code, to "insert a prominent notice in each changed file stating how, when and where You changed that file.". It also forbids using the code "for illegal, immoral or improper purposes, or on pages containing illegal, immoral or improper material" which restricts a lot of possible uses because "immoral" and "improper" are very vague terms. It also does not state whether it is possible to use code under this license in a combination with other licenses or link it to programs licensed under other licenses, which is a problem because my program is largely GPL\MIT.
 
Regards,
Habufe
GeneralRe: LicensemvpSacha Barber24-Jul-11 23:47 
It is quite restrictive I guess, have not checked truth be told. Its just what gets applied when you write for codeproject.
 
I have no issues people doing anything with any of my articles code though. Go ahead
Sacha Barber
  • Microsoft Visual C# MVP 2008-2011
  • Codeproject MVP 2008-2011
Open Source Projects
Cinch SL/WPF MVVM

Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

Questionthe codememberiNemo20-Aug-10 1:44 
Hello, nice control, used it as quick fix for feature request Smile | :) , however i'm little confused, why the code for picking the pixel color is so complicated (any special reason)? For ex. this is what I came up with after a while:
 
instead of this combo:
 
<Image x:Name="ColorImage" Width="150" Height="150" 
        HorizontalAlignment="Center"
        VerticalAlignment="Top" Margin="2"
        Source="..\Resources\ColorSwatchSquare.png"/>
<Canvas x:Name="CanvImage" Width="150" Height="150" 
        HorizontalAlignment="Center"
        Background="Transparent"
        VerticalAlignment="Top" Margin="2"
        MouseDown="CanvImage_MouseDown"
        MouseUp="CanvImage_MouseUp"
        MouseMove="CanvImage_MouseMove">
    <Ellipse x:Name="ellipsePixel" Width="10" 
        Height="10" Stroke="Black" Fill="White" 
        Canvas.Left="0" Canvas.Top="0"/>
</Canvas>
 
I use this:
 
<Canvas x:Name="CanvImage" Width="150" Height="150" HorizontalAlignment="Center" Margin="2" VerticalAlignment="Top" 
        MouseMove="CanvImage_MouseMove"
        MouseDown="CanvImage_MouseDown"
        MouseUp="CanvImage_MouseUp">
    <Canvas.Background>
        <ImageBrush>
            <ImageBrush.ImageSource>
                <BitmapImage x:Name="swatchBitmap" UriSource="..\Resources\ColorSwatchSquare.png"/>
            </ImageBrush.ImageSource>
        </ImageBrush>
    </Canvas.Background>
    <Ellipse x:Name="ellipsePixel" Width="10" 
        Height="10" Stroke="Black" Fill="White" 
        Canvas.Left="0" Canvas.Top="0"/>
</Canvas>
 
and the modification of code behind:
 
private void SetSolidColor()
{
    try
    {
        var mousePos = Mouse.GetPosition(CanvImage).CoerceToRectangle(new Size(swatchBitmap.PixelWidth, swatchBitmap.PixelHeight));
 
        var pixel = new byte[4];
        swatchBitmap.CopyPixels(new Int32Rect((int)mousePos.X, (int)mousePos.Y, 1, 1), pixel, 4, 0);
                
        ellipsePixel.SetValue(Canvas.LeftProperty, (mousePos.X - (ellipsePixel.Width / 2)));
        ellipsePixel.SetValue(Canvas.TopProperty, (mousePos.Y - (ellipsePixel.Height / 2)));
        CanvImage.InvalidateVisual();
        SelectedColor = Color.FromArgb((byte)AlphaSlider.Value, pixel[2], pixel[1], pixel[0]);
    }
    catch
    {
        //not much we can do
    }
}
 
private void CanvImage_MouseMove(object sender, MouseEventArgs e)
{
    if (e.LeftButton == MouseButtonState.Pressed)
        SetSolidColor();
}
 
private void CanvImage_MouseDown(object sender, MouseButtonEventArgs e)
{
    SetSolidColor();
    CanvImage.CaptureMouse();
    //_isMouseDown = true;
}
 
private void CanvImage_MouseUp(object sender, MouseButtonEventArgs e)
{
    CanvImage.ReleaseMouseCapture();
    //_isMouseDown = false;
}
 
this runs much more efficient and also enables user to move cursor out of canvas and still get proper color preview etc
 
the CoerceToRectangle method is simple extension that just ensures that a point is within bounds (to avoid out of range exception in CopyPixels)
 
public static Point CoerceToRectangle(this Point position, Size rectangleSize)
{
    if (position.X < 0.0) position.X = 0.0;
    if (position.Y < 0.0) position.Y = 0.0;
 
    if (position.X >= rectangleSize.Width) position.X = rectangleSize.Width - 1.0;
    if (position.Y >= rectangleSize.Height) position.Y = rectangleSize.Height - 1.0;
 
    return position;
}

AnswerRe: the codemvpSacha Barber20-Aug-10 3:06 
Fair enough, I think it took me about 2 hours to create this control, so there may be better ways. Still sounds like you have it how you want it, so fair enough.
 
Actually I think the code that you refer to is to pick the initial color, which was not part of my orginal code, that was done by a reader later and I just included it.
Sacha Barber
  • Microsoft Visual C# MVP 2008-2010
  • Codeproject MVP 2008-2010
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

GeneralRe: the codememberiNemo20-Aug-10 13:55 
Ok, was just wondering whether that's intentional (more robust when using CroppedBitmap? etc), thx for sharing
GeneralEnabling User to enter RGB valuesmemberDennise14-Apr-10 6:36 
Hi, great job, thanks for posting it.
 
My question is....if I enable the RBG boxes to allow the user to enter the values, how could move the ellipse in the swatch to match the user's entry.
 
Right now it picks the color based on a mouse move, but to make it more flexible, I would like to do the reverse as well, let the user enter a color and move the ellipse within the swatch to where that color is (within a close range)
 
Thanks.
GeneralRe: Enabling User to enter RGB valuesmvpSacha Barber14-Apr-10 6:50 
REad the "More News" section at bottom of the article and look at that link, its got all you need.
Sacha Barber
  • Microsoft Visual C# MVP 2008-2010
  • Codeproject MVP 2008-2010
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

GeneralRe: Enabling User to enter RGB valuesmemberDennise14-Apr-10 8:28 
Thanks for the tip, exactly what I was looking for.
GeneralhigroupSarafuddin18-Jan-10 6:21 
hi, i have posted a color picker for WPF. I hope you would comment on it as i am a big fan of yours in the world of WPF. You really rock the WPF world. Learn't many great stuff from your articles and blags Smile | :) .
GeneralRe: himvpSacha Barber18-Jan-10 6:23 
Got a link?
 
Sacha Barber
  • Microsoft Visual C# MVP 2008/2009
  • Codeproject MVP 2008/2009
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

GeneralRe: higroupSarafuddin18-Jan-10 6:26 
oh sorry i forgot to give the link. Here is it : WPF Color Picker Like Office 2007[^]
GeneralShould have been called 'WPF: Beautiful Color Picker'memberTheArchitectmc4-Jan-10 5:58 
Wink | ;)
GeneralRe: Should have been called 'WPF: Beautiful Color Picker'mvpSacha Barber4-Jan-10 6:02 
Yeah its ok, though you should look at Mark Treadwells work too. His added selecting color from initial color.
 
Sacha Barber
  • Microsoft Visual C# MVP 2008/2009
  • Codeproject MVP 2008/2009
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

GeneralGood StuffmemberMark Treadwell3-Jan-10 1:56 
I just came across this and it is worth a 5!
 
I modified the control and dialog to support an initial color as well as some other changes to fit it into my current project. My blog post on the changes is here[^]. The search for the color when opening with an initial color specified (to set the position of the cursor ellipse) takes some time. The search algorithm may be able to be improved, but it works for my current needs.
 
Mark Treadwell
Special Enhancements

GeneralRe: Good StuffmvpSacha Barber3-Jan-10 3:38 
You can not download the code associated with your blog can you fix that, and let me know and I'll amend this article to point people there. BUt I can only do that when I know the link to your revised code works.
 
At the moment it is ftp://ftp.narboza.com/files/WPFColorPicker.zip[^] and wants some FTP credentials. Boo
 
Let me know when you have a public link available and I will amend this article with link to your blog (which sounds cool), and will more than likely please a lot of people.
 
Sacha Barber
  • Microsoft Visual C# MVP 2008/2009
  • Codeproject MVP 2008/2009
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

GeneralRe: Good StuffmemberMark Treadwell3-Jan-10 4:15 
Sorry 'bout that. I pasted in the wrong link. The correct one is http://www.narboza.com/files/WPFColorPicker.zip.
 
Mark Treadwell
Special Enhancements

GeneralRe: Good StuffmvpSacha Barber3-Jan-10 9:42 
cool I'll update this article and mention your post when I get a chance, should not be too long, maybe tomorrow
 
Sacha Barber
  • Microsoft Visual C# MVP 2008/2009
  • Codeproject MVP 2008/2009
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

GeneralRe: Good StuffmvpSacha Barber4-Jan-10 5:33 
Thanks Mark,
 
Article updated now. Thanks for letting me know man.
 
Sacha Barber
  • Microsoft Visual C# MVP 2008/2009
  • Codeproject MVP 2008/2009
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

GeneralRe: Good Stuffmemberalk010-Feb-11 20:53 
Unfortunately, http link doesn't work, either.
 
(I was so happy staring at the list of improvements you made ;( )
GeneralRe: Good StuffmemberMark Treadwell11-Feb-11 2:10 
The HTTP link is working again. (A recent website update had deleted the file.)
Mark Treadwell
Special Enhancements

GeneralRe: Good Stuffmemberalk011-Feb-11 4:24 
Cool, really! Thanks!
GeneralCool! But I miss a SetIntialColor() Methodmemberbanjoji1-Jul-09 0:05 
Very cool Control!
 
There's one thing I miss:
 
I'd like to initialize the Colorpicker with a specific color (not always black Smile | :) ). So I added a simple setter into your code. It works well, except for the fact that the "ellipsePixel" (the small circle on the image showing which color is chosen) isn't positioned at the right place - do you have any suggestion how to solve this?
 
Thx!
GeneralRe: Cool! But I miss a SetIntialColor() MethodmvpSacha Barber4-Jan-10 5:34 
Mark Treadwell above has solved this and article is now up to date to point to his blog post.
 
Sacha Barber
  • Microsoft Visual C# MVP 2008/2009
  • Codeproject MVP 2008/2009
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

GeneralOn Lee Brimelow codememberOleg V. Polikarpotchkin30-May-09 17:50 
Hi Sacha,
I just posted the WPF Image Pixel Color Picker Element article where the Lee Brimelow technique you use in your article is enhanced a bit. Take a look, please!
Regards,
Oleg V. Polikarpotchkin
 
ovp

Generalthanksmemberahmad35820-Mar-09 19:30 
Realy thanks.
 
istgah,ایستگاه,نیازمندیها, نیازمندی, آگهی, رایگان, تبلیغات, ایران, مجانی,ایستگاه آگهی,تبلیغ,ایستگاه آگهی, آگهی رایگان, نیازمندیها, ارسال آگهی, تبلیغات, تبلیغات رایگان www.istgah100.com
GeneralRe: thanksmvpSacha Barber20-Mar-09 21:45 
no worries
 
Sacha Barber
  • Microsoft Visual C# MVP 2008/2009
  • Codeproject MVP 2008/2009
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

GeneralLicensememberclemi10-Feb-09 17:09 
Hi Sacha Barber. Your demo is splendid. I am using your Pulse button in part of my project.
 
As there are no explict license, can I know if I can use it commercially?
 
Thank you.
GeneralRe: LicensemvpSacha Barber10-Feb-09 21:48 
Of course you can use it commercially, no problems at all, if you do though could you just put a note about the original source, thats all I ask.
 
Sacha Barber
  • Microsoft Visual C# MVP 2008
  • Codeproject MVP 2008
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

GeneralCoolmemberMember 416352410-Feb-09 1:16 
How abt selecting linear gradients
GeneralRe: CoolmvpSacha Barber10-Feb-09 1:29 
I assume you mean GradientStop points for a LinearGradientBrush, if you do that could be made using another control that allowed user to pick the colorstop points using this control.
 
Thats not what I wanted to do, but you could do that as I suggested. This picks a single color, and that is all it should do I feel.
 
Its a color picker after all.
 
Sacha Barber
  • Microsoft Visual C# MVP 2008
  • Codeproject MVP 2008
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

GeneralFantastic ControlmvpAbhijit Jana3-Feb-09 3:22 
Nice control boss. 5 from me Smile | :)
 
You can developed another Color Picker Control like Blend Color Picker Wink | ;)
 
cheers,
Abhijit
CodeProject MVP
My Recent Article : Exploring Session in ASP.Net

GeneralRe: Fantastic ControlmvpSacha Barber3-Feb-09 3:37 
Abhijit Jana wrote:
You can developed another Color Picker Control like Blend Color Picker

 
yeah right, now do you remember Blend when it was still called Expression Interactive Designer, now that had the best color picker of all, have a look here
 
http://i.msdn.microsoft.com/Aa663364.introducingwpf8(ko-kr,MSDN.10).gif That was cool color picker.
 
Mine is really a cheat.
 
Sacha Barber
  • Microsoft Visual C# MVP 2008
  • Codeproject MVP 2008
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

GeneralAwesome!!memberDr.Luiji3-Feb-09 0:58 
Another excelent control by Sacha!!
5 forever
Thanks for sharing.
 
Dr.Luiji
 
Trust and you'll be trusted.
 
Try iPhone UI [^] a new fresh face for your Windows Mobile, here on Code Project.

GeneralRe: Awesome!!mvpSacha Barber3-Feb-09 1:00 
Thanks chap
 
Sacha Barber
  • Microsoft Visual C# MVP 2008
  • Codeproject MVP 2008
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

GeneralEven in a snow stormmemberDaniel Vaughan2-Feb-09 8:16 
Lol, I see you take advantage of all situations, including snow storms, to write article. Awesome work!
 
Cheers,
Daniel
 
Daniel Vaughan
Blog: DanielVaughan.Orpius.com

GeneralRe: Even in a snow stormmvpSacha Barber2-Feb-09 10:19 
Thanks Daniel. See you were right I did write a Color Picker after all.
 
Sacha Barber
  • Microsoft Visual C# MVP 2008
  • Codeproject MVP 2008
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

QuestionCancel colour selection?memberAdrian Cole2-Feb-09 7:39 
Very cool, professional looking control. One thing that seems to be missing is the ability to see what a colour would look like without selecting it. It would be nice to see the traditional OK and Cancel buttons.
AnswerRe: Cancel colour selection?mvpSacha Barber2-Feb-09 10:20 
Doh, captain cockup has marched to town, I will do that as soon as I can. Can't believe I missed that.
 
I feel very stupid.
 
Sacha Barber
  • Microsoft Visual C# MVP 2008
  • Codeproject MVP 2008
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

GeneralRe: Cancel colour selection?memberXmen W.K.4-Mar-11 23:32 
Laugh | :laugh: Laugh | :laugh: Laugh | :laugh:

TVMU^P[[IGIOQHG^JSH`A#@`RFJ\c^JPL>;"[,*/|+&WLEZGc`AFXc!L
%^]*IRXD#@GKCQ`R\^SF_WcHbORY87֦ʻ6ϣN8ȤBcRAV\Z^&SU~%CSWQ@#2
W_AD`EPABIKRDFVS)EVLQK)JKQUFK[M`UKs*$GwU#QDXBER@CBN%
R0~53%eYrd8mt^7Z6]iTF+(EWfJ9zaK-i’TV.C\y<pŠjxsg-b$f4ia>
-----------------------------------------------
128 bit encrypted signature, crack if you can

AnswerRe: Cancel colour selection?mvpSacha Barber2-Feb-09 10:39 
I have now fixed the article and the code, thanks for the heads up on that, I missed it. Doh.
 
Sacha Barber
  • Microsoft Visual C# MVP 2008
  • Codeproject MVP 2008
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

GeneralNicemembermainardineto2-Feb-09 5:41 
Very well done once more...
 
But... 2 great articles in 2 days? OMG | :OMG: is Sacha even human?Confused | :confused:
 
kidding... Smile | :) while you keep em comming I will keep reading and learning..
 
Thanks for another great piece of work. Got my 5, as usual...
 
btw: I like your design skills, simple yet good looking...
 
Raul
GeneralRe: NicemvpSacha Barber2-Feb-09 7:10 
I think I am part Borg or something.
 
See this link http://www.degraeve.com/img2txt-yay.php?url=http%3A%2F%2Ftbn1.google.com%2Fimages%3Fq%3Dtbn%3Aga2FyFiLxgmb5M%3Ahttp%3A%2F%2Fwww.huntingtondma.com%2Fwp-content%2Fuploads%2Fborg76.jpg&mode=A&size=100&charstr=ABCDEFGHIJKLMNOPQRSTUVWXYZ&order=O&invert=N
 
Sacha Barber
  • Microsoft Visual C# MVP 2008
  • Codeproject MVP 2008
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

GeneralRe: Nice [modified]membermainardineto2-Feb-09 7:56 
ok... didnt knew that... watch out for Picard(http://en.wikipedia.org/wiki/Jean-Luc_Picard[^]) ok? still got much to learn from you...
 
Wait.. Star Trek jokes in a Dev Community... how nerd are we anyway? Laugh | :laugh:
 
and would you mind to chat about an issue that I am curently facing? i tried some approaches already but i couldnt find a solution, maybe you could help me out... my email is rmainardineto@gmail.com
 
Thanks again for the article Sacha "Borgber"
 
Raul
 
modified on Monday, February 2, 2009 2:05 PM

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

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130617.1 | Last Updated 18 Apr 2012
Article Copyright 2009 by Sacha Barber
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid