Silverlight Navigation Frame in F#

This is again a quick post based on my daily findings as I work more into Silverlight and other frameworks with F#. The Silverlight Navigation Frame allows us to provide deep linking within Silverlight applications. It uses a NavigationFrame control and hosts a “Page” instead of UserControl. This is very useful when developing large enterprise apps and also provides SEO friendly URIs (if you are building something online).

I faced a couple of problems when using F#, because the Navigation frames were based purely on XAML code and it interacted with the C# code using partial classes. As you all know F# doesn’t provide “partial” classes, I was looking to find an alternative to customize this design. Luckily with Silverlight 4, the navigation frame includes a “ContentLoader” property which is of type INavigationContentLoader. It has some extensible methods that allows customization to define the mapping, that was it and I implemented the below code to wrap it around Types instead of plain URIs. This would allow the navigation frame to invoke an object of the type and then we load the Page in the implementation of the type. This lets us use F# code purely with XAML to be used for UI declaration.

type TypeContentLoader() =
    
    let getTypeNameFromUri(uri : Uri) =
        let mutable contentUri = uri
        if not(uri.IsAbsoluteUri) then
            contentUri <- new Uri(new Uri("dummy:///", UriKind.Absolute), uri.OriginalString)
        Uri.UnescapeDataString(contentUri.AbsolutePath.Substring(1))

    interface INavigationContentLoader with
    
        member x.CanLoad(targetUri : Uri, currentUri : Uri) =
            let typeName = getTypeNameFromUri(targetUri)
            let t = Type.GetType(typeName, false, true)
            let mutable result = true
            if t = null then
                result <- false
            let defaultConstructor = t.GetConstructor(Array.empty<Type>)
            if defaultConstructor = null then
                result <- false
            result

        member x.CancelLoad(asyncResult : IAsyncResult) =
            ()

        member x.BeginLoad(targetUri : Uri, currentUri : Uri, userCallback : AsyncCallback, asyncState : obj) =
            let t = Type.GetType(getTypeNameFromUri(targetUri), false, true)
            let instance = Activator.CreateInstance(t)         
            let asyncResult = new AsyncResultNoResult(userCallback, asyncState)   
            asyncResult.Result <- instance
            asyncResult.SetAsCompleted(null, true)
            upcast asyncResult            
            
        member x.EndLoad(asyncResult : IAsyncResult) =
            let container = asyncResult : ?> AsyncResultNoResult            
            new LoadResult(container.Result)

 

We simply set the navigation frame’s ContentLoader property with the above instance,

        <sdk:Frame x:Name="ContentFrame"
                   Grid.Row="1">
            <sdk:Frame.ContentLoader>
                <common:TypeContentLoader />
            </sdk:Frame.ContentLoader>
        </sdk:Frame>

 

Then declare a HyperlinkButton to navigate to the particular type,

            <HyperlinkButton Content="Home"
                             NavigateUri="FSharpSilverlightApp1.Home"
                             TargetName="ContentFrame"
                             Margin="4" />

That’s it, It is now easy to separate your view concerns based on namespaces. Hope this helps in using F# more easily!

Download the sample from here.

-Fahad

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: