App Mock Up

App Mock Up

You are toying with an idea of creating a new app. If you are not replicating functionality of some other app, you would go through the process of visualizing your idea in the form of app UI. You don’t want to jump into code at this time but want to feel how information in the app will be placed and how it will look inside the screen boundaries. This process is a pre-cursor to UX development or full-fledged wire-frame creation. This process of visualizing the idea takes some time before you are confident about how you want to take your app forward and jump into some sort of coding. Paper+pen or whiteboard+marker are good way to work through fluid ideas and layout information. This is not the phase when you are working on UX or designing UI, but just laying out ideas in rough screens. I personally like drawing and love to draw on paper/whiteboard. It is difficult to work with physical media if you are going through multiple iterations and changes (owing to fluid nature of this phase), even if you are good at drawing. For the reason of sheer manageability I would rather go for some GUI authoring tool with which I can directly drag+drop shapes, connect them, group them, size them and play around with ideas. Using GUI authoring tool is cleaner and easier if you are not into drawing. There are many such tools available out there with their strengths and weaknesses. Microsoft Office Visio, Sketch Flow, Concept.ly, Balsamiq Mockups, etc are some of the popular mockup creation tools. In this post I will talk about Pencil.

[Side note] If you are into SketchFlow and Windows Phone app development, you will find my project template useful. Check it out here. In following episode on Channel 9 Brian talks about my project at 06:12 mark.

Pencil is an open-source and free GUI authoring tool. With Pencil you can quickly create mockups and walkthroughs. Pencil is flexible to extend. It has pre-built basic shapes and also platform specific shapes (Visio calls them stencils, Pencil calls them shape collections) like Web, iOS, and Android. But you could make a mockup for Windows Phone as well. For this post I quickly created this panorama concept with Nokia Lumia, Windows Phone-

WPPencilWireFrame

This mockup is created with Sketchy GUI collection. Sketchy is a nice visual representation of ideation phase. In Pencil you have choice to use other standard and straight shapes. Shapes are flexible for customization to your requirement.

Pencil is a nice and simple tool. For small sized apps and quick ideation processes Pencil is very good. Pencil does not automatically generate code. Though it does generate clickable HTML but they are static HTML’s, not controls. Pencil is not good if your ideation process goes large and you have more than 10 screens to mockup in a single document (you will keep multiple screens in one document because you want to link them for click-through). With more than 10 screens in a single document Pencil goes very slow, painfully slow. Also, it seems, Pencil community may not be actively updating it. Last update was in 2012. If these things bother you, look at Sketch Flow or you might want to consider Visio. You can get 90 day trial of Microsoft Office Visio for free here.

For quick and small ideation process I liked Pencil, with its current abilities. I will soon try to do a quick video on basic tasks in Pencil.

C#|.NET Query String in Uri

C#|.NET Query String in Uri

In a not-so-basic-application you might have pages which are used for multiple similar purposes. You pass query string with many fields with multiple values between such pages (or web pages). In database driven apps, parameter values could be user generated and stored in the back-end and you pull more info from database on the basis of the value in query parameter. This is not the scenario of back-end driven app. This is more about “Field Names” and Values, which are part of the design and known to you while coding, and you want to manage them effectively and make the code more readable.

Let’s take an example:

You have a page in your app which loads different lists (ex: city, state, pin, salutation, etc.) and lets user select an item from the list. At different places in your app you pop this page up with required parameters to load appropriate items. The call to page looks something like this:

this.NavigationService.Navigate("/ListPicker.xaml?ListType=city",UriKind.Relative)

Let’s assume your page also has the ability for editing and you want to activate appropriate functionality (select only || edit). You would add one more parameter to your query, like so:

this.NavigationService.Navigate("/ListPicker.xaml?ListType=city&FormType=select",UriKind.Relative)

If you have many such pages, each have multiple fields and their multiple values, and you make calls to these pages from different places in your code, soon it will be very difficult to manage hard-coded query strings in Uri’s.

Here comes enum based solution:

We will have enums for fields and their values. For the purpose of this example we will keep single enum for fields and multiple enums for values for different fields. Let’s code
First define enums for fields and their values:

        internal enum QueryFields { ListPicker_FormType, ListPicker_ListType };
        internal enum ListTypes { City, States, Zip, Salutation };
        internal enum FormTypes { Select, Edit };

If you do not wish to be more detailed, you could simply build your Uri’s like so:

This.NavigationService.Navigate("/ListPicker.xaml?{0}={1}",QueryFields.ListPicker_FormType.ToString(), FormTypes.Select.ToString());
//The resultant uri - /ListPicer.xaml?ListPicker_FormType=Select

We will see below how you could parse query parameters in the called page and retrieve values in enum types.

Creating Uri as above still has string formatting which is not easy to maintain in multiple uses. To make things manageable and less error prone, let’s create a new enum for pages in the app and shift Uri building code in a single method which could be called from anywhere in the app with different field and values.

        internal enum AppPages {ListPicker, Setting, Main, etc };
        internal static Uri GetUri(AppPages appPage, params KeyValuePair<string, string>[] args)
        {
            string uriString = "";
            switch (appPage)
            {
                case AppPages.ListPicker:
                    uriString = "/Views/ListPicker.xaml";
                    break;
                case AppPages.Setting:
                    uriString = "/Views/Settings.xaml";
                    break;
                case AppPages.Main:
                    uriString = "/Main.xaml";
                    break;
                default:
                    uriString = "/Main.xaml";
                    break;
            }
            int counter = 0;
            string seperator = "?";
            foreach(KeyValuePair<string, string> query in args)
            {
                if (counter > 0) seperator = "&";
                uriString = String.Format("{0}{1}{2}={3}", uriString, seperator, query.Key, query.Value);
            }
            return new Uri(uriString, UriKind.Relative);
        }

With GetUri, you could create page navigation Uri with enums only instead of hard-coded strings:

            KeyValuePair<string, string> query_1 = new KeyValuePair<string,string>(QueryFields.ListPicker_FormType.ToString(), FormTypes.Select.ToString());
            KeyValuePair<string, string> query_2 = new KeyValuePair<string,string>(QueryFields.ListPicker_ListType.ToString(), ListTypes.City.ToString());
            This.NavigationService.Navigate(GetUri(AppPages.ListPicker, query_1, query_2));

Once you are navigated to your page, you need to parse query strings and extract enums which you could use in the page to decide page’s functionality.

At page level you need to have required enum type fields. For this example we will have two fields, one FormTypes type and other ListTypes type. A private processQuery method which accepts a dictionary sets these two fields appropriately.

        FormTypes formType;
        ListTypes listType;
        private void processQuery(Dictionary<string, string> query)
        {
            string _formTypeName = "";
            string _listTypeName = "";
            query.TryGetValue(QueryFields.ListPicker_FormType.ToString(), out _formTypeName);
            query.TryGetValue(QueryFields.ListPicker_ListType.ToString(), out _listTypeName);
            if (_formTypeName.Length != 0) formType = (FormTypes)(Convert.ToInt32(_formTypeName));
            if (_listTypeName.Length != 0) listType = (ListTypes)(Convert.ToInt32(_listTypeName));
        }

You would call processQuery method from OnNavigatedTo method of your page.

        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            Dictionary<string, string> _params = new Dictionary<string, string>(NavigationContext.QueryString);
            processQuery(new Dictionary<string, string>());
        }

If you have 100’s of case statements (to choose a page) in GetUri, and you are concerned about performance, refactore the method to accept page name with path as string. With page path name directly in string, you would not need case statements. By the way, in my case with about 80+ cases to get PageName, the query creation does not take more than 50MS, which is negligible for me. More so, navigation calls are not recursive ones.

Transparent Live Tile For Windows Phone 8.1

Transparent Live Tile For Windows Phone 8.1

Windows Phone 8.1 Dev Preview

Windows Phone 8.1 developer preview is totally awesome. So what is one of the most important things app devs can do right away, without much fuss, to make their apps look great with Windows Phone 8.1? Revisit your app’s Live Tile images. Why? In 8.1, Start screen is mesmerizing with the parallax effect and Live Tile with background overlay. Dev preview users are going crazy with new Start experience, and I am sure, with public release, end users are going to love to have background image as well. Take a look at this awesome Nokia Lumia 925 Start screen:

wp_ss_20140416_0015[1]

When users have a background image, they might not like to have solid Live Tiles block their beautiful background. So, revisit your app’s Live Tile images – all of them! Check if they are transparent or not? If they are like Cortana, Avirall Time Suite, etc. in the image above, you are all set. You can safely ignore this article and find some other awesome way to improve your app for WP8.1 (think Cortana). If they are not, I suggest to update ‘em ASAP. And it’s easy, too. Let’s see how you can create transparent Live Tile images with Open Source Inkscape. You could choose to use Paint.NET (not MS Paint), Photoshop, GIMP, or any other tool which allows you to export image with transparency. Though I prefer GIMP for image editing but I chose Inkscape for this demo. Let’s go.

Step 1: Setup the page

InkScape01

  1. Open Inkscape and create a new document and Open Document Properties from file menu.
  2. In most cases app icons are solid white, if yours is one too, change the background color of the page, temporarily, to light yellow. This is while working only so that you can see white color. Before exporting we will reset this to transparent (this is very important).
  3. This example is for 336 X 336 medium tile. So set the custom size to 336 X 336.
  4. Make sure Units is “px”.

Step 2: Setup the drawing

InkScape02

Windows Phone 8 Asset Template Guide suggests a 336 X 336 tile to have 110px margin on all sides. Create 110px margin guides on all the sides. To create margin guides click and drag from the horizontal ruler on the top and from the vertical ruler on the left.

Step 3: Create Live Tile image of your app

InkScape03

The center part between the margins is the space where your tile image will go. Create your image here. For this example I simply dragged the box from tool box and made a hole in it 😀

Step 4: Set background to transparent

InkScape03a

To create a transparent Live Tile image we would like to have a transparent background. Go back in document properties and set Background to transparent by resetting “A” to 0. If your image is solid white, you might not see anything after making the background transparent. Don’t worry, your image is there (maybe somebody can tell how working space (not document background) in Inkscape can be made a different color than white).

Step 5: Export

InkScape04

  1. Open Export dialog from File > Export Bitmap…
  2. Set X0, X1, Y0, Y1 as shown in the image above.
  3. Browse for the image location, and make sure you give “PNG” as the extension of the image, NOT JPG or BMP.
  4. Export. (Alternatively, as suggested by Austin Andrews, you could export as SVG, and use his awesome service!)

Step 6: Check Final Image

WindowsPhotoViewer05

Notice that your final image does not have a white background. Windows Photo Viewers’s light blue background is your image’s background.

You are done. You would want to change all Live Tile images of your app in the same way. A transparent Live Tile image will encourage users to have your app pinned to Start screen without obstructing their beautiful background images.

Respect your users!

Download Lumia 925 Emulator Skin

Have you seen this feature demo video of Avirall? (jump to 00:50)

Do you like the emulator? This is Visual Studio Windows Phone Nokia Lumia 925 emulator skin, i created :D.

Nokia925_UP

You can also create your own app demo video with this skin! Download this skin from here.

Instructions about how to apply skin to your emulator are here.

Happy skinning, oops!

C# : Properties and Serialization

Protected by mikecogh, on Flickr
Protected, a photo by mikecogh on Flickr.

Does your app serialize (on IS or for wire-travelling) model entities to JSON/XML? Did you come across a scenario where you want to ensure that a property is, though serialize-able but should not be settable from the code? For example ID property. Your model class creates this ID internally and it also gets serialized. For it being serialize-able, it is required that the properly is public, but then you expose it to other parts of code as well and make it vulnerable for accidental edits. EditorBrowsableAttribute is not the solution here because of two reasons; one it does not work with the code inside your project, second if it did work, it’s still only hiding from IntelliSense and not stopping you from setting the property in code.
I tackle this scenario in my Nokia Lumia app by having a super-class PersistentEntity and then derive all model classes from PersistentEntity class.
ClassDiagram
PersistentEntity has two properties related to serialization – WriteState and ReadState which are of PersistencyStates enumeration type. PersistencyStates enum has following members – None, WritePending, Queued (because all serialization takes place on BG thread), Writing, Written, Read, and Reading. In case of serializing an entity, as soon as any changes made to the object, the object goes in WritePending, and from there it changes state from Queued to Writing, to Written state. Every other property in derived class which needs to be exposed for serialization only, ensures that in setter sets the value SavingState is “Saving”. If it is not, throw an invalid operation exception with proper message. Let’s have a look at the code.

PersistencyStates enumerator:

    public enum PersistencyStates
    {
        None, WritePending, Queued, Writing, Written, Reading, Read
    }

This is the super class PersistentEntity:

   public class PersistentEntity : ISerializable
    {
        [NonSerialized] //for Silverlight this is IgnoreDataMember attribute
        public PersistencyStates WriteState { get; private set; }
        [NonSerialized] //for Silverlight this is IgnoreDataMember attribute
        public PersistencyStates ReadState { get; private set; }

        #region serialization related methods
        [OnDeserializing]
        public void OnDeSerializingEntity(StreamingContext context)
        {
            this.WriteState = PersistencyStates.Writing;
        }
        [OnDeserialized]
        public void OnDeSerializedEntity(StreamingContext context)
        {
            this.WriteState = PersistencyStates.Written;
            //do something else if required
            this.WriteState = PersistencyStates.None;
        }
        [OnSerializing]
        public void OnSerializingEntity(StreamingContext context)
        {
            this.ReadState = PersistencyStates.Reading;
        }
        [OnSerialized]
        public void OnSerializedEntity(StreamingContext context)
        {
            this.ReadState = PersistencyStates.Read;
        }
        #endregion //serialization related methods


        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            //do nothing;
        }
    }

This is the derived class TestEntity have a property ID which is ensured to update only while serialization:

   class TestEntity : PersistentEntity
    {
        private Guid _id = Guid.NewGuid();
        public Guid ID 
        {
            get 
            {
                return _id;
            }
            set
            {
                if (this.WriteState == PersistencyStates.Writing)
                {
                    _id = value;
                }
                else
                {
                    throw new InvalidOperationException("Cannot set ID from outside", new Exception("MyCompany.MVVM.Model.TestEntity.ID has public setter for the purpose of serialization only. Not designed to be set from outside of the class."))
                }
            }
        }
    }

I hope I could make the intent and implementation clear.

C# Extension: Random Pastel Colors

C# Extension: Random Pastel Colors

In last post we wrote extension method to get complementary color of a given color. In this post we will write some more extension methods to get colors. Co-incidentally India is totally covered in colors because this is the Holi week.
If you want to have a dynamic feel to your app (or some part of your app) you could fill it with random colors. Let’s write following extension methods which return random color with parameterized control over what type of color output you need:

  • Color.GetRandom – This method returns a random color.
  • Color.GetRandom(Brightness Control) – This method returns a random color between given brightness.
  • Color.GetRandomShade – This returns a random color of the Color’s shade.
  • Color.GetRandomShade(Brightness Control) – It returns a random color of given color between given brightness.
  • Color.GetPastelShade() – Returns a pastel shade of given color.

Let’s code.
We will utilize the same code from our last post and extend the ColorExtensions class. To implement aforesaid methods, add following code to the said class

        static Random randomizer = new Random();
        /// <summary>
        /// Returns a pastel shade of the color
        /// </summary>
        /// <param name="source">Source  color</param>
        /// <returns></returns>
        public static Color GetPastelShade(this Color source)
        {
            return (generateColor(source, true, new HSB { H = 0, S = 0.2d, B = 255 }, new HSB { H = 360, S = 0.5d, B = 255 }));
        }
        /// <summary>
        /// Returns a random color
        /// </summary>
        /// <param name="source">Ignored(Use RandomShade to get a shade of given color)</param>
        /// <returns></returns>
        public static Color GetRandom(this Color source)
        {
            return (generateColor(source, false, new HSB { H = 0, S = 0, B = 0 }, new HSB { H = 360, S = 1, B = 255 }));
        }
        /// <summary>
        /// Returns a random color within a brightness boundry
        /// </summary>
        /// <param name="source">Ignored (Use GetRandomShade to get a random shade of the color)</param>
        /// <param name="minBrightness">A valued from 0.0 to 1.0, 0 is darkest and 1 is lightest</param>
        /// <param name="minBrightness">A valued from 0.0 to 1.0</param>
        /// <returns></returns>
        public static Color GetRandom(this Color source, double minBrightness, double maxBrightness)
        {
            if (minBrightness >= 0 && maxBrightness <= 1)
            {
                return (generateColor(source, false, new HSB { H = 0, S = 1 * minBrightness, B = 255 }, new HSB { H = 360, S = 1 * maxBrightness, B = 255 }));
            }
            else
            {
                throw new ArgumentOutOfRangeException();
            }
        }
        /// <summary>
        /// Returns a random shade of the color
        /// </summary>
        /// <param name="source">Base color for the returned shade</param>
        /// <returns></returns>
        public static Color GetRandomShade(this Color source)
        {
            return (generateColor(source, true, new HSB { H = 0, S = 1, B = 0 }, new HSB { H = 360, S = 1, B = 255 }));
        }
        /// <summary>
        /// Returns a random color within a brightness boundry
        /// </summary>
        /// <param name="source">Base color for the returned shade</param>
        /// <param name="minBrightness">A valued from 0.0 to 1.0, 0 is brightest and 1 is lightest</param>
        /// <param name="minBrightness">A valued from 0.0 to 1.0</param>
        /// <returns></returns>
        public static Color GetRandomShade(this Color source, double minBrightness, double maxBrightness)
        {
            if (minBrightness >= 0 && maxBrightness <= 1)
            {
            return (generateColor(source, true, new HSB { H = 0, S = 1 * minBrightness, B = 255 }, new HSB { H = 360, S = 1 * maxBrightness, B = 255 }));
            }
            else
            {
                throw new ArgumentOutOfRangeException();
            }
        }
        /// <summary>
        /// Process parameters and returns a color
        /// </summary>
        /// <param name="source">Color source</param>
        /// <param name="isaShadeOfSource">Should source be used to generate the new color</param>
        /// <param name="min">Minimum range for HSB</param>
        /// <param name="max">Maximum range for HSB</param>
        /// <returns></returns>
        private static Color generateColor(Color source, bool isaShadeOfSource, HSB min, HSB max)
        {
            HSB hsbValues = ConvertToHSB(new RGB { R = source.R, G = source.G, B = source.B });
            double h_double = randomizer.NextDouble();
            double s_double = randomizer.NextDouble();
            double b_double = randomizer.NextDouble();
            if (max.B - min.B == 0) b_double = 0; //do not change Brightness
            if(isaShadeOfSource)
            {
                min.H = hsbValues.H;
                max.H = hsbValues.H;
                h_double = 0;
            }
            hsbValues = new HSB
            {
                H = Convert.ToDouble(randomizer.Next(Convert.ToInt32(min.H), Convert.ToInt32(max.H))) + h_double,
                S = Convert.ToDouble((randomizer.Next(Convert.ToInt32(min.S * 100), Convert.ToInt32(max.S * 100)))/100d),
                B = Convert.ToDouble(randomizer.Next(Convert.ToInt32(min.B), Convert.ToInt32(max.B))) + b_double
            };
            Debug.WriteLine("H:{0} | S:{1} | B:{2} [Min_S:{3} | Max_S{4}]", hsbValues.H,_hsbValues.S,_hsbValues.B, min.S, max.S) ;
            RGB rgbvalues = ConvertToRGB(_hsbValues);
            return new Color { A = source.A, R = (byte)_rgbvalues.R, G = (byte)_rgbvalues.G, B = (byte)_rgbvalues.B };
        }

You could call these methods like so:

Color randomPurplishPastel = Colors.Purple.GetPastelShade();

Here is an example :

My app uses random colors pretty extensively:

Avirall Time Suite | Nokia Lumia 1520

Holi hai!!!

C# Extension: Complementary Color

C# Extension: Complementary Color

In the image above blue & orange are complementary colors, green and red are complementary colors, purple and yellow are complementary colors, etc. The formula is; two colors, placed exactly opposite to each other on color wheel are complementary. You use complementary color combination to highlight a particular item in your design. For example, if most part of your screen has blue color, for important elements on the screen you would choose orange color. Photographers and painters know about importance of complementary color in making their paintings and photographs beautiful:

Complementary Colors by OneEighteen, on Flickr
Complementary Colors, a photo by OneEighteen on Flickr.

In case your app design is dynamic which gives control to the user to choose a dominant color in your app, e.g. background color, you would want to know the contrast color of the chosen color on-the-fly. Particularly in Windows Phone apps, if you incorporate user selected accent color in app design, for some important elements you might need contrast color. For example, in following screenshot of my app, the accent color on the phone is magenta and the color of the hands, auto generated in code, is green.

QSQIn1020Small

This extension method of Color class returns the contrast color:
(HSB and RGB conversion code courtesy, Yi-Lun Luo)

namespace MyCompany.AwesomeExtensions.MediaHelpers
{
    public static class ColorExtensions
    {
        static Random randomizer = new Random();
        public static Color GetContrast(this Color source, bool preserveOpacity)
        {
            Color inputColor = source;
            //if RGB values are close to each other by a diff less than 10%, then if RGB values are lighter side, decrease the blue by 50% (eventually it will increase in conversion below), if RBB values are on darker side, decrease yellow by about 50% (it will increase in conversion)
            byte avgColorValue = (byte)((source.R + source.G + source.B) / 3);
            int diff_r = Math.Abs(source.R - avgColorValue);
            int diff_g = Math.Abs(source.G - avgColorValue);
            int diff_b = Math.Abs(source.B - avgColorValue);
            if (diff_r < 20 && diff_g < 20 && diff_b < 20) //The color is a shade of gray
            {
                if (avgColorValue < 123) //color is dark
                {
                    inputColor.B = 220;
                    inputColor.G = 230;
                    inputColor.R = 50;
                }
                else
                {
                    inputColor.R = 255;
                    inputColor.G = 255;
                    inputColor.B = 50;
                }
            }
            byte sourceAlphaValue = source.A;
            if (!preserveOpacity)
            {
                sourceAlphaValue = Math.Max(source.A, (byte)127); //We don't want contrast color to be more than 50% transparent ever.
            }
            RGB rgb = new RGB { R = inputColor.R, G = inputColor.G, B = inputColor.B };
            HSB hsb = ConvertToHSB(_rgb);
            hsb.H = hsb.H < 180 ! hsb.H + 180 : hsb.H - 180;
            //hsb.B = isColorDark ? 240 : 50; //Added to create dark on light, and light on dark
            rgb = ConvertToRGB(_hsb);
            return new Color { A = sourceAlphaValue, R = rgb.R, G = (byte)rgb.G, B = (byte)rgb.B };
        }
        internal static RGB ConvertToRGB(HSB hsb)
        {
            // By: <a href="http://blogs.msdn.com/b/codefx/archive/2012/02/09/create-a-color-picker-for-windows-phone.aspx" title="MSDN" target="_blank">Yi-Lun Luo</a>
            double chroma = hsb.S * hsb.B;
            double hue2 = hsb.H / 60;
            double x = chroma * (1 - Math.Abs(hue2 % 2 - 1));
            double r1 = 0d;
            double g1 = 0d;
            double b1 = 0d;
            if (hue2 >= 0 && hue2 < 1)
            {
                r1 = chroma;
                g1 = x;
            }
            else if (hue2 >= 1 && hue2 < 2)
            {
                r1 = x;
                g1 = chroma;
            }
            else if (hue2 >= 2 && hue2 < 3)
            {
                g1 = chroma;
                b1 = x;
            }
            else if (hue2 >= 3 && hue2 < 4)
            {
                g1 = x;
                b1 = chroma;
            }
            else if (hue2 >= 4 && hue2 < 5)
            {
                r1 = x;
                b1 = chroma;
            }
            else if (hue2 >= 5 && hue2 <= 6)
            {
                r1 = chroma;
                b1 = x;
            }
            double m = hsb.B - chroma;
            return new RGB()
            {
                R = r1 + m,
                G = g1 + m,
                B = b1 + m
            };
        }
        internal static HSB ConvertToHSB(RGB rgb)
        {
           // By: <a href="http://blogs.msdn.com/b/codefx/archive/2012/02/09/create-a-color-picker-for-windows-phone.aspx" title="MSDN" target="_blank">Yi-Lun Luo</a>
            double r = rgb.R;
            double g = rgb.G;
            double b = rgb.B;

            double max = Max(r, g, b);
            double min = Min(r, g, b);
            double chroma = max - min;
            double hue2 = 0d;
            if (chroma != 0)
            {
                if (max == r)
                {
                    hue2 = (g - b) / chroma;
                }
                else if (max == g)
                {
                    hue2 = (b - r) / chroma + 2;
                }
                else
                {
                    hue2 = (r - g) / chroma + 4;
                }
            }
            double hue = hue2 * 60;
            if (hue < 0)
            {
                hue += 360;
            }
            double brightness = max;
            double saturation = 0;
            if (chroma != 0)
            {
                saturation = chroma / brightness;
            }
            return new HSB()
            {
                H = hue,
                S = saturation,
                B = brightness
            };
        }
        private static double Max(double d1, double d2, double d3)
        {
            if (d1 > d2)
            {
                return Math.Max(d1, d3);
            }
            return Math.Max(d2, d3);
        }
        private static double Min(double d1, double d2, double d3)
        {
            if (d1 < d2)
            {
                return Math.Min(d1, d3);
            }
            return Math.Min(d2, d3);
        }
        internal struct RGB
        {
            internal double R;
            internal double G;
            internal double B;
        }
        internal struct HSB
        {
            internal double H;
            internal double S;
            internal double B;
        }
    }
}

Get working code from my GitHub repository (POCs).