Thursday, April 09, 2009

Silverlight with F#: Managing embedded resources

One of my blog reader asked why I inline XAML instead of putting it into a separate file and hooking up the variables manually in F#.  My answer was laziness: I did not spend the time to figure out how. (If you subscribe to Larry Wall’s philosophy, laziness is a virtue …)  Well, that question prompted me to look into how to externalize the xaml file and load it in.  This dovetailed nicely with recipe 2.14 of the book Silverlight 2 Recipes, which shows how to load embedded resources.  I put the xaml code in a separate file called page.xaml and added the following compiler flag:

 --resource page.xaml

Here’s the xaml file:


<Canvas
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="LayoutRoot" Background="White">
<TextBlock>Hi There Reader</TextBlock>
<TextBlock Canvas.Left="20" Canvas.Top="20">Hi There</TextBlock>
<TextBlock Canvas.Left="40"
Canvas.Top="40">Silverlight</TextBlock>
<TextBlock Canvas.Left="60" Canvas.Top="60">
Silverlight</TextBlock>
<TextBlock Canvas.Left="80" Canvas.Top="80">
Silverlight</TextBlock>
<TextBlock Canvas.Left="100" Canvas.Top="100">
Silverlight</TextBlock>
</Canvas>

Here's the code that loads the xaml file and hook the control with a variable:


#light
namespace SilverLightFSharp

open System
open System.Resources
open System.Reflection
open System.IO
open System.Windows
open System.Windows.Browser
open System.Windows.Controls
open System.Windows.Markup
open List

// Recipe 2-14 and XAML from Recipe 3-3 of the Silverlight 2 Recipes book
type MyPage() = class
inherit UserControl()

do

let assembly = Assembly.GetExecutingAssembly();
let sr = new StreamReader(assembly.GetManifestResourceStream("page.xaml"));
let xamlControls = sr.ReadToEnd()

// Load xaml dynamically
let canvas = XamlReader.Load(xamlControls) :?> Canvas


base.Width <- 400.0
base.Height <- 300.0
base.Content <- canvas
end

type ErrorPage = class
inherit UserControl

new (msg:string ) as this = {} then

let textarea = new TextBlock(Text=msg,
TextWrapping=TextWrapping.Wrap,
Margin=new Thickness(4.0,4.0,4.0,4.0))

let sp = new StackPanel(HorizontalAlignment = HorizontalAlignment.Stretch,
Margin=new Thickness(8.0,8.0,10.0,8.0))
sp.Children.Add(textarea)

base.Width <- 600.0
base.Height <- 1000.0
base.Content <- sp
end


type MyApp = class
inherit Application

new () as this = {} then
this.Startup.Add(fun _ ->
let rootPanel = new StackPanel()
try
this.RootVisual <- rootPanel
rootPanel.Children.Add(new MyPage())
with _ as e ->
let msg = e.Message + e.StackTrace
rootPanel.Children.Clear()
rootPanel.Children.Add(new ErrorPage(msg)))

this.UnhandledException.Add(fun args ->
args.Handled <- true
try
let msg = args.ExceptionObject.Message + args.ExceptionObject.StackTrace
let errmsg = msg.Replace('"','\'').Replace("\r\n",@"\n")
"throw new Error(\"Unhandled error in Silverlight 2 Application " + msg + "\");"
|> HtmlPage.Window.Eval |> ignore
with _ -> HtmlPage.Window.Eval("throw new Error(\"Custom Error!\");") |> ignore)
end

1 comment:

electronic signature in word said...

Grateful to check out your website, I seem to be ahead to more excellent sites and I wish that you wrote more informative post for us. Well done work.