F#でXamarin.Formsを使う

いつからできるようになったんだっけ?

Petzold Book Blog – Writing Xamarin.Forms Apps in F#
http://www.charlespetzold.com/blog/2015/10/Writing-Xamarin-Forms-Apps-in-FSharp.html

なところなので、実は随分前からある。

で、Visual Studio for Mac の「Blank Forms App」で F# が選べるようになっていたので試してみる。ちなみに、Windows のほうの Visual Studio 2017 には F# のテンプレートがないので、Mac で作ったものを Windows 側にコピーしている。

テンプレートが少しおかしいらしく、Android のほうの Xamarin.Forms が入らない(入れようとしてエラーになっている)ので手動で入れる。

Mac のほうで作るので UWP のプロジェクトはない。
きちんと *.xaml があるので、XAML がロードできる。

type SampleXFormsFPage() = 
    inherit ContentPage()
    let xaml = base.LoadFromXaml(typeof<SampleXFormsFPage>)

C# だと、自動生成された *.g.cs ファイルにLoadFromXamlがあって、内部的にクラスとXAMLをマッチングさせる。で、F# の場合は *.g.fs を生成しないので、これを直接使うという訳。

いわゆる x:Name がプロパティにマッピングされないので、自前で FindByName を呼び出す。OnAddメソ\ッドは、動的にリフレクションを使っているのか、AddHandler を使わずにマッピングされる。UWP の場合は、Click に対応するイベントコードが生成されるが、Xamarin.Forms の場合は、イベントが生成されないのでビルド時にはチェックされず、実行時に対応するイベントがないと例外が発生する。これは C# も F# も同じ。

namespace SampleXFormsF

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

type TodoItem() =
    member val Id = &quot;&quot; with get, set 
    member val Name = &quot;&quot; with get, set
    member val Done = false with get, set

type SampleXFormsFPage() = 
    inherit ContentPage()
    let _ = base.LoadFromXaml(typeof<SampleXFormsFPage>)
    let todoList = base.FindByName<ListView>(&quot;todoList&quot;)
    let newItemName = base.FindByName<Entry>(&quot;newItemName&quot;)
    let items = new System.Collections.ObjectModel.ObservableCollection<TodoItem>()

    do
        todoList.ItemsSource <- items

    override this.OnAppearing() = 
        base.OnAppearing()

    member this.OnAdd( sender : obj, e : EventArgs ) =
            let item = new TodoItem()
            item.Id <- Guid.NewGuid().ToString()
            item.Name <- newItemName.Text
            items.Add( item )

    member this.OnSelected( sender : obj, e : SelectedItemChangedEventArgs ) = ()
    member this.OnRefresh( sender : obj, e : EventArgs ) =  ()
    member this.OnComplete( sender : obj, e : EventArgs ) =  ()

XAML はこんな感じ。もともと、Mobile App のクイックスタートのコードを持ってきているので、後から Azure に対応させる。

<?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?>
<ContentPage xmlns=&quot;http://xamarin.com/schemas/2014/forms&quot; xmlns:x=&quot;http://schemas.microsoft.com/winfx/2009/xaml&quot; xmlns:local=&quot;clr-namespace:SampleXFormsF&quot; x:Class=&quot;SampleXFormsF.SampleXFormsFPage&quot;>
    <Grid RowSpacing=&quot;0&quot;>
        <Grid.RowDefinitions>
            <RowDefinition Height=&quot;Auto&quot; />
            <RowDefinition Height=&quot;*&quot; />
        </Grid.RowDefinitions>
        <ActivityIndicator Grid.RowSpan=&quot;2&quot; HorizontalOptions=&quot;Center&quot; VerticalOptions=&quot;Center&quot; IsVisible=&quot;False&quot; IsEnabled=&quot;True&quot; x:Name=&quot;syncIndicator&quot;/>
        <StackLayout Grid.Row=&quot;0&quot; BackgroundColor=&quot;#5ABAFF&quot; Padding=&quot;10,30,10,5&quot;>
            <Label TextColor=&quot;#555555&quot; Text=&quot;Azure App Service&quot; />
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition Width=&quot;Auto&quot;/>
                </Grid.ColumnDefinitions>
                <Entry x:Name=&quot;newItemName&quot; Placeholder=&quot;Item name&quot; />
                <StackLayout x:Name=&quot;buttonsPanel&quot; Grid.Column=&quot;1&quot; Orientation=&quot;Horizontal&quot; HorizontalOptions=&quot;StartAndExpand&quot;>
                    <Button Text=&quot;+&quot; MinimumHeightRequest=&quot;30&quot; Clicked=&quot;OnAdd&quot; />
                </StackLayout>
            </Grid>
        </StackLayout>
        <ListView x:Name=&quot;todoList&quot; ItemSelected=&quot;OnSelected&quot; IsPullToRefreshEnabled=&quot;true&quot; Refreshing=&quot;OnRefresh&quot; Grid.Row=&quot;1&quot;>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <ViewCell.ContextActions>
                            <MenuItem Clicked=&quot;OnComplete&quot; Text=&quot;Complete&quot; CommandParameter=&quot;{Binding .}&quot;/>
                        </ViewCell.ContextActions>
                        <StackLayout HorizontalOptions=&quot;StartAndExpand&quot; Orientation=&quot;Horizontal&quot; Padding=&quot;15,5,0,0&quot;>
                            <StackLayout Padding=&quot;5,0,0,0&quot; VerticalOptions=&quot;StartAndExpand&quot; Orientation=&quot;Vertical&quot;>
                                <Label Text=&quot;{Binding Name}&quot; />
                            </StackLayout>
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</ContentPage>

実行してみる


ちなみに、フロントが C# でも良いならば、適当な UWP プロジェクトを取ってきて、F# の PCL を参照設定することで動作できる。

カテゴリー: 開発, F#, Xamarin パーマリンク