Today I am discussing about the WPF colorizer using F#. The application will show that how you can change color of rectangles by editing edge colors and main colors in combination of Red, Green, Blue (r,g,b). You can add more colors to the F# colorizer by this application.Steps for edit colors in colorizer are given below.

Step 1: Firstly open a new project in F# using Visual Studio 2011. Select F# WPF application template and give name to the project like below Image.

New Project Dialog Box

Step 2: Now add below define References to the Project by right clicking on the Project in Solution Explorer.

Step 3: When you add all these references your solution explorer will look like below image.

Solution Explorer

Step 4: Now click on Programe.fs file and write below Code in that like below image.

colorizer code part1

colorizer code part1.1

colorizer code part1.1.1

colorizer code part1.1.1.1

open System.Windows
open System.Windows.Controls
open System.Windows.Data
open System.Windows.Media
open System.Windows.Shapes
open Microsoft.Win32

type IIndexable<'a> =
abstract member Item : int -> 'a

let makeBinding(sourceObj:obj, sourcePath:string, converter:'T->'U,
targetObj:DependencyObject, targetDependencyProperty:DependencyProperty) =
let b = new System.Windows.Data.Binding()
b.Source <- sourceObj
b.Path <- new System.Windows.PropertyPath(sourcePath)
b.Converter <-
{ new System.Windows.Data.IValueConverter with
member this.Convert(v, targetType, param, culInfo) =
box(converter (unbox v))
member this.ConvertBack(v, targetType, param, culInfo) =
raise <| new System.NotImplementedException() }
BindingOperations.SetBinding(targetObj, targetDependencyProperty, b) |> ignore

type MyWindow() as this =
inherit Window()

static let selectedRectangleNumber =
DependencyProperty.Register("SelectedRectangleNumber", typeof<int>, typeof<MyWindow>,
new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(fun depObj ea ->
match box depObj, box ea.NewValue with
| (:? MyWindow as w), (:? int as x) -> w.TriggerSelectedRectangleNumberChanged(x)
| _ -> ())))

let selectedChanged = new Event<Handler<int>,int>()
let getNum() = this.GetValue(MyWindow.SelectedRectangleNumber) :?> int
let setNum(n) = this.SetValue(MyWindow.SelectedRectangleNumber, n)

let colors =
try
let key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\VisualStudio\10.0\Text Editor\FSharpDepthColorizer")
Array.init 10 (fun i -> key.GetValue(sprintf "Depth%d" i) :?> string)
|> Array.map (fun s -> let [|r1; g1; b1; r2; g2;b2|] = s.Split[|','|] |> Array.map byte
r1,g1,b1,r2,g2,b2)
with e ->
[| // greyscale colors
190uy,190uy,190uy,230uy,230uy,230uy
170uy,170uy,170uy,210uy,210uy,210uy
184uy,184uy,184uy,224uy,224uy,224uy
164uy,164uy,164uy,204uy,204uy,204uy
178uy,178uy,178uy,218uy,218uy,218uy
158uy,158uy,158uy,198uy,198uy,198uy
172uy,172uy,172uy,212uy,212uy,212uy
152uy,152uy,152uy,192uy,192uy,192uy
166uy,166uy,166uy,206uy,206uy,206uy
146uy,146uy,146uy,186uy,186uy,186uy
|]
// why the SolidColorBrush below?
// to have a DependencyObject to data-bind... there is probably a cleaner way, but oh well
let edgeColors = colors |> Array.map (fun (r,g,b,_,_,_) -> SolidColorBrush(Color.FromRgb(r,g,b)))
let mainColors = colors |> Array.map (fun (_,_,_,r,g,b) -> SolidColorBrush(Color.FromRgb(r,g,b)))
let brushes =
let makeGradientStop(b:SolidColorBrush, pct) =
let gs = new GradientStop(b.Color, pct)
makeBinding(b, "Color", (fun (c:Color) -> c), gs, GradientStop.ColorProperty)
gs
{ new IIndexable<Brush> with
member this.Item depth =
upcast new LinearGradientBrush(
new GradientStopCollection(
[|
makeGradientStop(edgeColors.[depth], 0.0)
makeGradientStop(mainColors.[depth], 0.01)
makeGradientStop(mainColors.[depth], 1.0)
|] ), new Point(0.0, 0.5), new Point(1.0, 0.5)) }

let printCurrentSettings() =
printfn "Windows Registry Editor Version 5.00"
printfn ""
printfn "[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\10.0\Text Editor\FSharpDepthColorizer]"
for i in 0..9 do
let ec = edgeColors.[i].Color
let mc = mainColors.[i].Color
printfn "\"Depth%d\"=\"%d,%d,%d,%d,%d,%d\"" i ec.R ec.G ec.B mc.R mc.G mc.B

let mkButton(colors:SolidColorBrush[], text, dr, dg, db) =
let b = new Button()
b.Content <- text
b.Click.Add(fun _ -> colors.[getNum()].Color <-
Color.FromRgb(colors.[getNum()].Color.R + byte dr,
colors.[getNum()].Color.G + byte dg,
colors.[getNum()].Color.B + byte db))
b

let mkButtonPanel(colors:SolidColorBrush[],text,dr,dg,db,f) =
let panel = new StackPanel(Orientation = Orientation.Horizontal)
let tb = new TextBlock()
selectedChanged.Publish.Add(fun _ ->
makeBinding(colors.[getNum()], "Color", (fun (c:Color) -> f(c).ToString()),
tb, System.Windows.Controls.TextBlock.TextProperty))
panel.Children.Add(mkButton(colors, text+" down",-dr,-dg,-db)) |> ignore
panel.Children.Add(tb) |> ignore
panel.Children.Add(mkButton(colors, text+" up",dr,dg,db)) |> ignore
panel

do
let leftPanel = new StackPanel(Orientation = Orientation.Vertical)
leftPanel.Children.Add(mkButtonPanel(edgeColors,"edge R",2,0,0,(fun c->c.R))) |> ignore
leftPanel.Children.Add(mkButtonPanel(edgeColors,"edge G",0,2,0,(fun c->c.G))) |> ignore
leftPanel.Children.Add(mkButtonPanel(edgeColors,"edge B",0,0,2,(fun c->c.B))) |> ignore
leftPanel.Children.Add(mkButtonPanel(mainColors,"main R",2,0,0,(fun c->c.R))) |> ignore
leftPanel.Children.Add(mkButtonPanel(mainColors,"main G",0,2,0,(fun c->c.G))) |> ignore
leftPanel.Children.Add(mkButtonPanel(mainColors,"main B",0,0,2,(fun c->c.B))) |> ignore
//let printButton = new Button(Content="Print current settings to console")
//printButton.Click.Add(fun _ -> printCurrentSettings())
//leftPanel.Children.Add(printButton) |> ignore
let mainPanel = new StackPanel(Orientation = Orientation.Horizontal)
mainPanel.Children.Add(leftPanel) |> ignore
let canvas = new Canvas()
for i in 0..mainColors.Length-1 do
let rect = new Rectangle(Width=600., Height=500., Fill = brushes.[i])
rect.MouseDown.Add(fun _ -> setNum(i))
Canvas.SetLeft(rect, (float i)*30.)
Canvas.SetTop(rect, (float i)*30.)
Canvas.SetZIndex(rect, i)
canvas.Children.Add(rect) |> ignore
let rect = new Rectangle(Width=600., Height=40.)
selectedChanged.Publish.Add(fun _ -> rect.Fill <- brushes.[getNum()])
Canvas.SetLeft(rect, 0.)
Canvas.SetTop(rect, (float mainColors.Length)*30. + 20.)
Canvas.SetZIndex(rect, mainColors.Length)
canvas.Children.Add(rect) |> ignore
mainPanel.Children.Add(canvas) |> ignore
this.Content <- mainPanel


member private this.TriggerSelectedRectangleNumberChanged(x:int) = selectedChanged.Trigger(this, x)

static member SelectedRectangleNumber = selectedRectangleNumber

[<System.STAThread>]
do
(new Application()).Run(MyWindow()) |> ignore

Step 5: Now press F5 to execute the code and your application is ready.

Firstly click on any of the rectangle than select edge color or main color your color will be edited.

Output

colorizer output1

colorizer output2

colorizer output3

colorizer output4

colorizer output5

colorizer output6

Summary

In this article I have discussed that how can you create a colorizer in WPF using F#.