Jamie Dixon
Jamie Dixon

Reputation: 4292

F#: How to navigate between pages in Xamarin.Forms

I I have created a main page like this:

namespace Foo

open System
open Xamarin.Forms
open Xamarin.Forms.Xaml

type MainPage() =
    inherit ContentPage()
    let _ = base.LoadFromXaml(typeof<MainPage>)
    let baseLayout = base.Content :?> AbsoluteLayout
    let backgroundImage = baseLayout.Children.[0] :?> Image
    let navigatonGrid = baseLayout.Children.[1] :?> Grid
    let navigatonImage = navigatonGrid.Children.[0] :?> Image
    let navigatonButton = navigatonGrid.Children.[1] :?> Button

    let onButtonClicked sender args =
        let loginPage = new NavigationPage(FacebookLoginPage())
        Navigation.PushAsync(loginPage) |> ignore


    let populateImages =
        backgroundImage.Source <- ImageSource.FromResource("foo.jpg")
        navigatonImage.Source <- ImageSource.FromResource("bar.jpg")

    do
        populateImages
        navigatonButton.Clicked.AddHandler(new EventHandler(onButtonClicked))

And I wrap the Content page in the App.xaml.fs like this:

namespace foo

open Xamarin.Forms

type App() =
    inherit Application(MainPage = NavigationPage(MainPage()))

However, it does not compile. I get this:

/Users/jamesdixon/Projects/foo/foo/MainPage.xaml.fs(9,9): Error FS0039: The value, namespace, type or module 'Navigation' is not defined. Maybe you want one of the following: NavigationPage
navigatonGrid navigatonButton navigatonImage
NavigationEventArgs (FS0039) (foo.Mobile.iOS)

However, I can't add the "this" keyword because I get this error:

/Users/jamesdixon/Projects/foo/foo.Mobile/MainPage.xaml.fs(9,9): Error FS0039: The value, namespace, type or module 'this' is not defined. Maybe you want one of the following: ThisAssembly (FS0039) (SameRoom.foo.iOS)

Is the problem that the button click cannot be static? If so, what is the correct syntax for the event handler?

Update: Based on the comments below, I tried this:

open System
open Xamarin.Forms
open Xamarin.Forms.Xaml

type MainPage(x) as self =
    inherit ContentPage()
    let _ = base.LoadFromXaml(typeof<MainPage>)

But now I get

The type 'ContentPage' is not defined

Upvotes: 1

Views: 277

Answers (2)

Charles Roddie
Charles Roddie

Reputation: 947

Use a self-identifier:

type MainPage() as this =

Upvotes: 3

Tyler Hartwig
Tyler Hartwig

Reputation: 660

I suspect that this is due to F# methods being translated to static methods (at least that's my understanding). The static method doesn't have access to the base type's method.

If you define onButtonClicked as follows, it should work for you

member this.onButtonClicked sender args =
    let loginPage = new NavigationPage(FacebookLoginPage())
    this.Navigation.PushAsync(loginPage) |> ignore

Using the member this.onButtonClicked syntax creates a class method, rather than a static method on the class. This then lets you access this.Navigation on the class as you expect.

As for your problem with the constructor ordering, there are two solutions:

This link should explain how to do it in the constructor: https://fsharpforfunandprofit.com/posts/classes/#accessing-the-instance-via-this-in-a-do-block

However, according to that article, this is bad practice, an alternative would be to assign the handler in the OnStart or PageAppearing Lifecycle methods of the page.

Upvotes: 2

Related Questions