いつからできるようになったんだっけ?
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 = "" with get, set
member val Name = "" with get, set
member val Done = false with get, set
type SampleXFormsFPage() =
inherit ContentPage()
let _ = base.LoadFromXaml(typeof<SampleXFormsFPage>)
let todoList = base.FindByName<ListView>("todoList")
let newItemName = base.FindByName<Entry>("newItemName")
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="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:SampleXFormsF" x:Class="SampleXFormsF.SampleXFormsFPage">
<Grid RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ActivityIndicator Grid.RowSpan="2" HorizontalOptions="Center" VerticalOptions="Center" IsVisible="False" IsEnabled="True" x:Name="syncIndicator"/>
<StackLayout Grid.Row="0" BackgroundColor="#5ABAFF" Padding="10,30,10,5">
<Label TextColor="#555555" Text="Azure App Service" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Entry x:Name="newItemName" Placeholder="Item name" />
<StackLayout x:Name="buttonsPanel" Grid.Column="1" Orientation="Horizontal" HorizontalOptions="StartAndExpand">
<Button Text="+" MinimumHeightRequest="30" Clicked="OnAdd" />
</StackLayout>
</Grid>
</StackLayout>
<ListView x:Name="todoList" ItemSelected="OnSelected" IsPullToRefreshEnabled="true" Refreshing="OnRefresh" Grid.Row="1">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.ContextActions>
<MenuItem Clicked="OnComplete" Text="Complete" CommandParameter="{Binding .}"/>
</ViewCell.ContextActions>
<StackLayout HorizontalOptions="StartAndExpand" Orientation="Horizontal" Padding="15,5,0,0">
<StackLayout Padding="5,0,0,0" VerticalOptions="StartAndExpand" Orientation="Vertical">
<Label Text="{Binding Name}" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</ContentPage>
実行してみる
ちなみに、フロントが C# でも良いならば、適当な UWP プロジェクトを取ってきて、F# の PCL を参照設定することで動作できる。





