In Windows Phone (Silverlight) there is no System.Drawing.ColorTranslator.FromHtml(“#cccccc”); or similar that can help you convert a hex string into a color object. To do this you’ll have to parse the string yourself.
So is a simple method that will do so, it supports both “argb” and “rgb” with or without “#” in front of it. Meaning: The string “#aabbcc” or “#ffaabbcc” or “aabbcc” or “ffaabbcc” will be converted to a Color object.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
private static Regex _hexColorMatchRegex = new Regex("^#?(?<a>[a-z0-9][a-z0-9])?(?<r>[a-z0-9][a-z0-9])(?<g>[a-z0-9][a-z0-9])(?<b>[a-z0-9][a-z0-9])$", RegexOptions.IgnoreCase | RegexOptions.Compiled); public static Color GetColorFromHex(string hexColorString) { if (hexColorString == null) throw new NullReferenceException("Hex string can't be null."); // Regex match the string var match = _hexColorMatchRegex.Match(hexColorString); if (!match.Success) throw new InvalidCastException(string.Format("Can't convert string \"{0}\" to argb or rgb color. Needs to be 6 (rgb) or 8 (argb) hex characters long. It can optionally start with a #.", hexColorString)); // a value is optional byte a = 255, r = 0, b = 0, g = 0; if (match.Groups["a"].Success) a = System.Convert.ToByte(match.Groups["a"].Value, 16); // r,b,g values are not optional r = System.Convert.ToByte(match.Groups["r"].Value, 16); b = System.Convert.ToByte(match.Groups["b"].Value, 16); g = System.Convert.ToByte(match.Groups["g"].Value, 16); return Color.FromArgb(a, r, g, b); } |
ValueConverter for Xaml
Since I will be using this in Xaml databinding I created a ValueConverter for it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public class ColorHexStringToBrushConverter : IValueConverter { public static Dictionary<string, Brush> _brushCache = new Dictionary<string, Brush>(); public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var colorStr = ((string)value).ToLower(); lock (_brushCache) { if (!_brushCache.ContainsKey(colorStr)) _brushCache.Add(colorStr, new SolidColorBrush(colorStr.HexStringToColor())); return _brushCache[colorStr]; } } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotSupportedException("Converting back from image not supported."); } // Copy paste code from above } |
Note that because I will be using a fairly low number of different colors I have added a (thread safe) “_brushCache” dictionary. This will speed up reuse of same color codes as its not necessary to parse the string and recreate Color and SolidBrush objects every time the color is used.
Usage
Add resource
To use this converter in databinding first add it as a resource.
- Recompile project. After any change to codebehind that affects Xaml (such as creating a new “ColorHexStringToBrushConverter” class) you need to recompile once. If not Visual Studio Xaml editor will complain that the object doesn’t exist.
-
Inside the “<PhoneApplicationPage …>” or “<UserControl …>” tag you need to append a namespace reference, for example if converter is in namespace “YourProject.Utils”:
1 2 3 |
<Application ... existing stuff ... xmlns:utils="clr-namespace:YourProject.Utils"> |
- Inside “<UserControl.Resources>” (add it before first “<Grid>” if it doesn’t exist already) add:
1 2 3 |
<UserControl.Resources> <utils:ColorHexStringToBrushConverter x:Key="ColorHexStringToBrushConverter" /> </UserControl.Resources> |
Databind with Converter
Then in your page / user control where you databind simply add “Converter={StaticResource ColorHexStringToBrushConverter }” to your databinding.
For example:
1 |
<Button Content="Databound background color!" Background="{Binding color, Converter={StaticResource ColorHexStringToBrushConverter }}" /> |
As String extension method
You could add it as a string extension method:
1 2 3 4 |
public static Color HexToColor(this string hexColorString) { return GetColorFromHex(hexColorString); } |
And then use it as:
1 |
Color color = "#cc11cc".HexToColor(); |
When deserializing
Warning: The following section is untested. Added it just for fun.
You can create an object type of it that can be used more directly.
1 2 3 4 |
HexColorBrush hexColorBrush = “#aabbcc”; HexColorBrush hexColorBrush = new HexColorBrush(“aabbcc”); HexColorBrush hexColorBrush = Color.Red; HexColorBrush hexColorBrush = new HexColorBrush(Color.Red); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
public class HexColorBrush : Brush { public static readonly DependencyProperty ColorProperty = DependencyProperty.Register("Color", typeof(Color), typeof(HexColorBrush), new PropertyMetadata(false)); public Color Color { get { return (Color)base.GetValue(ColorProperty); } set { base.SetValue(ColorProperty, value); } } public HexColorBrush() : base() { } public HexColorBrush(string value) : this(Utils.ExtensionMethods.GetColorFromHex(value)) { } public HexColorBrush(Color value) : this() { this.Color = value; } public static implicit operator HexColorBrush(string value) { return new HexColorBrush(value); } public static implicit operator HexColorBrush(Color value) { return new HexColorBrush(value); } } |
This line:
return Color.FromArgb(a, r, b, g);
Should be
return Color.FromArgb(a, r, g, b);
You have the a, r, g, b parameters in the wrong order
Thanks. Fixed. 🙂
Thanks for the solution, I faced the same problem today.
One remark: you have to compose your color in this way -> return Color.FromArgb(a, r, g, b);
Thanks. Fixed. 🙂