Thursday, November 08, 2007

Learning WPF with F# - Adding Contents

Going through Chapter 3 of Charles Petzold's "Applications = Code + Markup" book. The only new concepts while working through these examples is use of currying for modifyTextBehavior function in the ToggleBoldAndItalic example. The curried function allows me to replace the foreach statement in the original C# code with the Seq.iter to apply the curried function modifyBehavior to each word in the list.

In the general industry trend, this following article in eWeek Microsoft Puts the 'F' in Functional seems to present F# as a first-class citizen on .Net. Does this mean that we'll see F# comes bundled with Visual Studio?


DisplaySomeText


#light
#I @"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0"
#r @"WindowsBase.dll"
#r @"PresentationCore.dll"
#r @"PresentationFramework.dll"

open System
open System.Windows
open System.Windows.Input
open System.Windows.Media

(* From Chap 3 - DisplaySomeText.cs *)

type DisplaySomeText = class
inherit Window as base

new () as this = {} then
this.Title <- "Display Some Text"
this.Content <- "Content can be simple text!"

end

#if COMPILED
[<STAThread()>]
do
let app = new Application() in
app.Run(new DisplaySomeText()) |> ignore
#endif

RecordKeystrokes



#light
#I @"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0"
#r @"WindowsBase.dll"
#r @"PresentationCore.dll"
#r @"PresentationFramework.dll"

open System
open System.Windows
open System.Windows.Input
open System.Windows.Media

(* From Chap 3 - RecordKeystrokes.cs *)

type RecordKeystrokes = class
inherit Window as base

new () as this = {} then
this.Title <- "Record Keystrokes"
this.Content <- ""

// Introduce casting from object to string with ( :?> ) operator
// Used pattern matching instead of if/then/else statement
override this.OnTextInput (args:TextCompositionEventArgs) =
base.OnTextInput(args)
let str = this.Content :?> string
match args.Text with
| "\b" -> this.Content <- match str.Length with
| 0 -> ""
| _ -> str.Substring(0,str.Length-1)
| _ -> this.Content <- str + args.Text

end

#if COMPILED
[<STAThread()>]
do
let app = new Application() in
app.Run(new RecordKeystrokes()) |> ignore
#endif

ShowMyFace

#light
#I @"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0"
#r @"WindowsBase.dll"
#r @"PresentationCore.dll"
#r @"PresentationFramework.dll"

open System
open System.Windows
open System.Windows.Controls
open System.Windows.Input
open System.Windows.Media
open System.Windows.Media.Imaging

(* From Chap 3 - ShowMyFace.cs *)

type ShowMyFace = class
inherit Window as base

new () as this = {} then
this.Title <- "Show My Face"
this.Content <- ""

let uri = new Uri("http://www.charlespetzold.com/PetzoldTattoo.jpg")
let bitmap = new BitmapImage(uri)
let mutable img = new Image()
img.Source <- bitmap
this.Content <- img

end

#if COMPILED
[<STAThread()>]
do
let app = new Application() in
app.Run(new ShowMyFace()) |> ignore
#endif

ShapeAnEllipse

#light
#I @"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0"
#r @"WindowsBase.dll"
#r @"PresentationCore.dll"
#r @"PresentationFramework.dll"

open System
open System.Windows
open System.Windows.Controls
open System.Windows.Input
open System.Windows.Media
open System.Windows.Shapes

(* From Chap 3 - ShapeAnEllipse.cs *)

type ShapeAnEllipse = class
inherit Window as base

new () as this = {} then
this.Title <- "Shape an Ellipse"
let mutable elips = new Ellipse()
elips.Fill <- Brushes.AliceBlue
elips.StrokeThickness <- 24.0
elips.Stroke <- new LinearGradientBrush(Colors.CadetBlue,
Colors.Chocolate,
new Point(1.0, 0.0),
new Point(0.0, 1.0))
this.Content <- elips


end

#if COMPILED
[<STAThread()>]
do
let app = new Application() in
app.Run(new ShapeAnEllipse()) |> ignore
#endif

FormatTheText

#light
#I @"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0"
#r @"WindowsBase.dll"
#r @"PresentationCore.dll"
#r @"PresentationFramework.dll"

open System
open System.Windows
open System.Windows.Controls
open System.Windows.Input
open System.Windows.Media
open System.Windows.Documents

(* From Chap 3 - FormatTheText.cs *)

type FormatTheText = class
inherit Window as base

new () as this = {} then
this.Title <- "Format the Text"
let mutable txt = new TextBlock();
txt.FontSize <- 32.0;
txt.Inlines.Add("This is some ");
txt.Inlines.Add(new Italic(new Run("italic")));
txt.Inlines.Add(" text, and this is some ");
txt.Inlines.Add(new Bold(new Run("bold")));
txt.Inlines.Add(" text, and let's cap it off with some ");
txt.Inlines.Add(new Bold(new Italic(new Run("bold italic"))));
txt.Inlines.Add(" text.");
txt.TextWrapping <- TextWrapping.Wrap;
this.Content <- txt

end

#if COMPILED
[<STAThread()>]
do
let app = new Application() in
app.Run(new FormatTheText()) |> ignore
#endif

ToggleBoldAndItalic

#light
#I @"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0"
#r @"WindowsBase.dll"
#r @"PresentationCore.dll"
#r @"PresentationFramework.dll"

open System
open System.Windows
open System.Windows.Controls
open System.Windows.Input
open System.Windows.Media
open System.Windows.Documents

(* From Chap 3 - ToggleBoldAndItalic.cs *)

let modifyTextBehavior (text:TextBlock) word =
let run = new Run(word)
run.MouseDown.Add
(fun args -> match args.ChangedButton with
|MouseButton.Left -> if (run.FontStyle = FontStyles.Italic) then
run.FontStyle <- FontStyles.Normal
else
run.FontStyle <- FontStyles.Italic
|MouseButton.Right -> if (run.FontWeight = FontWeights.Bold ) then
run.FontWeight <- FontWeights.Normal
else
run.FontWeight <- FontWeights.Bold
|_ -> ()

)
text.Inlines.Add(run)
text.Inlines.Add(" ")


type ToggleBoldAndItalic = class
inherit Window as base

new () as this = {} then
this.Title <- "Toggle Bold & Italic"
let mutable text = new TextBlock();
text.FontSize <- 32.0;
text.HorizontalAlignment <- HorizontalAlignment.Center
text.VerticalAlignment <- VerticalAlignment.Center
this.Content <- text

let strQuote = "To be, or not to be, that is the question"
let strWords = strQuote.Split([|' '|])

// Currying the modifyTextBehavior function
let modifyBehavior = modifyTextBehavior text

// Replaces the foreach (string str in strWords) block
Seq.iter modifyBehavior strWords

end

#if COMPILED
[<STAThread()>]
do
let app = new Application() in
app.Run(new ToggleBoldAndItalic()) |> ignore
#endif

SimpleEllipse & RenderTheGraphic

#light
#I @"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0"
#r @"WindowsBase.dll"
#r @"PresentationCore.dll"
#r @"PresentationFramework.dll"

open System
open System.Windows
open System.Windows.Media

(* From Chap 3 - SimpleEllipse.cs *)
type SimpleEllipse = class
inherit FrameworkElement as base

new () as this = {}

override this.OnRender (dc:DrawingContext) =
dc.DrawEllipse(Brushes.Blue,
new Pen(Brushes.Red, 24.0),
new Point(this.RenderSize.Width / 2.0,
this.RenderSize.Height / 2.0),
this.RenderSize.Width / 2.0,
this.RenderSize.Height / 2.0)

end


(* From Chap 3 - RenderTheGraphic.cs *)
type RenderTheGraphic = class
inherit Window as base

new () as this = {} then
this.Title <- "Render the Graphic"
this.Content <- new SimpleEllipse()

end

#if COMPILED
[<STAThread()>]
do
let app = new Application() in
app.Run(new RenderTheGraphic()) |> ignore
#endif


2 comments:

Anonymous said...

"inherit Window as base" is invalid syntax for F# under VS2010

John Liao said...

Yes. The compiler has changed since I posted this blog entry. "base" was added as a keyword since F# version 1.9.4 as mentioned in Don Syme's blog. You can safely drop "as base" and everything should still work.