add generator, make simplificiations

This commit is contained in:
Don Syme 2018-04-23 11:42:13 +01:00
Родитель 6f1110a198
Коммит 0bd291718b
29 изменённых файлов: 2413 добавлений и 851 удалений

8
.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,8 @@
obj
bin
*.bak
.vs
.fake
packages
paket-files
*.dll

Просмотреть файл

@ -1,37 +0,0 @@
// Copyright 2018 Elmish.XamarinForms contributors. See LICENSE.md for license.
namespace Elmish.XamarinForms
open Elmish
open FSharp.Control
[<RequireQualifiedAccess>]
module Cmd =
let ofAsyncCallback (task: 'a -> ('b -> unit) -> Async<_>)
(arg: 'a)
(callback: 'b -> 'msg)
(ofSuccess: _ -> 'msg)
(ofError: _ -> 'msg) : Cmd<'msg> =
let bind dispatch =
async {
let cb = callback >> dispatch
let! r = task arg cb |> Async.Catch
dispatch (match r with
| Choice1Of2 x -> ofSuccess x
| Choice2Of2 x -> ofError x)
}
[bind >> Async.StartImmediate]
let dispatch d (cmd: Cmd<_>) = for sub in cmd do sub d
let ofAsyncSeq p : Cmd<_> =
[ fun dispatch -> p |> AsyncSeq.iter dispatch |> Async.StartImmediate ]
type CmdBuilder() =
inherit AsyncSeq.AsyncSeqBuilder()
member x.Run(p: AsyncSeq<_>) = ofAsyncSeq p
[<AutoOpen>]
module CommandBuidler =
let cmd = Cmd.CmdBuilder()

Просмотреть файл

@ -1,635 +0,0 @@
// Copyright 2018 Elmish.XamarinForms contributors. See LICENSE.md for license.
namespace Elmish.XamarinForms
open Xamarin.Forms
open Elmish
open Elmish.XamarinForms
open Elmish.XamarinForms.DynamicViews
/// Represents a model when you don't have a model. A Clayton's model.
type NoModel =
| NoModel
type Update<'model, 'msg> = 'msg -> 'model -> 'model * Cmd<'msg>
type Update<'model, 'msg, 'extmsg> = 'msg -> 'model -> 'model * Cmd<'msg> * 'extmsg
type StaticView<'model, 'msg, 'page> = unit -> 'page * ViewBindings<'model, 'msg>
type DynamicView<'model, 'msg, 'page> = unit -> 'page * ViewBindings<'model, 'msg> * ('model -> 'msg -> View)
[<AutoOpen>]
module Values =
let NoCmd<'a> : Cmd<'a> = Cmd.none
let mutable currentPage : Page = null
[<RequireQualifiedAccess>]
module Nav =
// TODO: modify the Elmish framework we use to remove this global state and pass it into all commands??
let mutable globalNavMap : Map<System.IComparable, Page> = Map.empty
/// Push new location into history and navigate there
let push (fromPageTag: ('navTarget :> System.IComparable)) (toPageTag: ('navTarget :> System.IComparable)) : Cmd<_> =
[ fun _ ->
let fromPage = globalNavMap.[fromPageTag]
let toPage = globalNavMap.[toPageTag]
let nav = fromPage.Navigation
nav.PushAsync toPage |> ignore ]
/// Push new location into history and navigate there
let pushModal (fromPageTag: ('navTarget :> System.IComparable)) (toPageTag: ('navTarget :> System.IComparable)) : Cmd<_> =
[ fun _ ->
let fromPage = globalNavMap.[fromPageTag]
let toPage = globalNavMap.[toPageTag]
let nav = fromPage.Navigation
nav.PushModalAsync toPage |> ignore ]
let popToRoot (fromPageTag: ('navTarget :> System.IComparable)) : Cmd<_> =
[ fun _ ->
let fromPage = globalNavMap.[fromPageTag]
let nav = fromPage.Navigation
nav.PopToRootAsync() |> ignore ]
let popModal (fromPageTag: ('navTarget :> System.IComparable)) : Cmd<_> =
[ fun _ ->
let fromPage = globalNavMap.[fromPageTag]
let nav = fromPage.Navigation
nav.PopModalAsync() |> ignore ]
let pop (fromPageTag: ('navTarget :> System.IComparable)) : Cmd<_> =
[ fun _ ->
let fromPage = globalNavMap.[fromPageTag]
let nav = fromPage.Navigation
nav.PopAsync() |> ignore ]
[<RequireQualifiedAccess>]
module Init =
let combo2 init1 init2 () =
let model1 = init1()
let model2 = init2()
(model1, model2)
let combo3 init1 init2 init3 () =
let model1 = init1()
let model2 = init2()
let model3 = init3()
(model1, model2, model3)
let combo4 init1 init2 init3 init4 () =
let model1 = init1()
let model2 = init2()
let model3 = init3()
let model4 = init4()
(model1, model2, model3, model4)
let combo5 init1 init2 init3 init4 init5 () =
let model1 = init1()
let model2 = init2()
let model3 = init3()
let model4 = init4()
let model5 = init5()
(model1, model2, model3, model4, model5)
[<RequireQualifiedAccess>]
module InitCmd =
let combo2 init1 init2 () =
let model1, cmd1 = init1()
let model2, cmd2 = init2()
(model1, model2), Cmd.batch [cmd1; cmd2]
let combo3 init1 init2 init3 () =
let model1, cmd1 = init1()
let model2, cmd2 = init2()
let model3, cmd3 = init3()
(model1, model2, model3), Cmd.batch [cmd1; cmd2; cmd3]
let combo4 init1 init2 init3 init4 () =
let model1, cmd1 = init1()
let model2, cmd2 = init2()
let model3, cmd3 = init3()
let model4, cmd4 = init4()
(model1, model2, model3, model4), Cmd.batch [cmd1; cmd2; cmd3; cmd4]
let combo5 init1 init2 init3 init4 init5 () =
let model1, cmd1 = init1()
let model2, cmd2 = init2()
let model3, cmd3 = init3()
let model4, cmd4 = init4()
let model5, cmd5 = init5()
(model1, model2, model3, model4, model5), Cmd.batch [cmd1; cmd2; cmd3; cmd4; cmd5]
[<RequireQualifiedAccess>]
module Update =
let combo2 (update1: Update<_, _, _>) (update2: Update<_, _, _>) : Update<_,_,_> = fun msg (model1, model2) ->
match msg with
| Choice1Of2 msg1 -> let newModel, cmds, extmsg = update1 msg1 model1 in (newModel, model2), Cmd.map Choice1Of2 cmds, extmsg
| Choice2Of2 msg2 -> let newModel, cmds, extmsg = update2 msg2 model2 in (model1, newModel), Cmd.map Choice2Of2 cmds, extmsg
let combo3 (update1: Update<_, _, _>) (update2: Update<_, _, _>) (update3: Update<_, _, _>) : Update<_,_,_> = fun msg (model1, model2, model3) ->
match msg with
| Choice1Of3 msg1 -> let newModel, cmds, extmsg = update1 msg1 model1 in (newModel, model2, model3), Cmd.map Choice1Of3 cmds, extmsg
| Choice2Of3 msg2 -> let newModel, cmds, extmsg = update2 msg2 model2 in (model1, newModel, model3), Cmd.map Choice2Of3 cmds, extmsg
| Choice3Of3 msg3 -> let newModel, cmds, extmsg = update3 msg3 model3 in (model1, model2, newModel), Cmd.map Choice3Of3 cmds, extmsg
let combo4 (update1: Update<_, _, _>) (update2: Update<_, _, _>) (update3: Update<_, _, _>) (update4: Update<_, _, _>) : Update<_,_,_> = fun msg (model1, model2, model3, model4) ->
match msg with
| Choice1Of4 msg1 -> let newModel, cmds, extmsg = update1 msg1 model1 in (newModel, model2, model3, model4), Cmd.map Choice1Of4 cmds, extmsg
| Choice2Of4 msg2 -> let newModel, cmds, extmsg = update2 msg2 model2 in (model1, newModel, model3, model4), Cmd.map Choice2Of4 cmds, extmsg
| Choice3Of4 msg3 -> let newModel, cmds, extmsg = update3 msg3 model3 in (model1, model2, newModel, model4), Cmd.map Choice3Of4 cmds, extmsg
| Choice4Of4 msg4 -> let newModel, cmds, extmsg = update4 msg4 model4 in (model1, model2, model3, newModel), Cmd.map Choice4Of4 cmds, extmsg
let combo5 (update1: Update<_, _, _>) (update2: Update<_, _, _>) (update3: Update<_, _, _>) (update4: Update<_, _, _>) (update5: Update<_, _, _>) : Update<_,_,_> = fun msg (model1, model2, model3, model4, model5) ->
match msg with
| Choice1Of5 msg1 -> let newModel, cmds, extmsg = update1 msg1 model1 in (newModel, model2, model3, model4, model5), Cmd.map Choice1Of5 cmds, extmsg
| Choice2Of5 msg2 -> let newModel, cmds, extmsg = update2 msg2 model2 in (model1, newModel, model3, model4, model5), Cmd.map Choice2Of5 cmds, extmsg
| Choice3Of5 msg3 -> let newModel, cmds, extmsg = update3 msg3 model3 in (model1, model2, newModel, model4, model5), Cmd.map Choice3Of5 cmds, extmsg
| Choice4Of5 msg4 -> let newModel, cmds, extmsg = update4 msg4 model4 in (model1, model2, model3, newModel, model5), Cmd.map Choice4Of5 cmds, extmsg
| Choice5Of5 msg5 -> let newModel, cmds, extmsg = update5 msg5 model5 in (model1, model2, model3, model4, newModel), Cmd.map Choice5Of5 cmds, extmsg
/// Reconcile external messages by turning them into changes in the composed model and/or commands
let reconcile f (update: Update<'model,'msg,'extmsg>) : Update<'model,'msg> = fun msg model ->
let newModel, cmds, extmsg = update msg model
let newModel2, cmds2 = f extmsg newModel
newModel2, Cmd.batch [cmds; cmds2]
[<RequireQualifiedAccess>]
module StaticView =
let internal setBindingContextsUntyped (bindings: ViewBindings<'model, 'msg>) (viewModel: ViewModel<obj, obj>) =
for (bindingName, binding) in bindings do
match binding with
| BindSubModel (ViewSubModel (initf, _, _, _, _)) ->
console.log (sprintf "view: seting data context for %s" bindingName)
let subModel = viewModel.[bindingName]
initf subModel
| _ -> ()
let internal setBindingContexts (bindings: ViewBindings<'model, 'msg>) (viewModel: ViewModel<'model, 'msg>) =
for (bindingName, binding) in bindings do
match binding with
| BindSubModel (ViewSubModel (initf, _, _, _, _)) ->
console.log (sprintf "view: seting data context for %s" bindingName)
let subModel = viewModel.[bindingName]
initf subModel
| _ -> ()
let internal pageInit (page: Page) contentf bindings (viewModel: ViewModel<'model, 'msg>) model dispatch =
setBindingContexts bindings viewModel
page.BindingContext <- box viewModel
match contentf with
| None -> None
| Some f ->
let viewData: XamlElement = f model dispatch
let contentPage = (page :?> ContentPage)
contentPage.Content <- viewData.CreateAsView()
Some viewData
let internal pageUpdate (page: Page) contentf model prevViewDataOpt dispatch =
match contentf, prevViewDataOpt with
| Some f, Some prevViewData ->
let viewData: XamlElement = f model dispatch
viewData.ApplyIncremental (prevViewData, (page :?> ContentPage).Content)
Some viewData
| _ ->
prevViewDataOpt
let internal pageInitUntyped (page: ContentPage) (bindings: ViewBindings<'model, 'msg>) =
fun (objViewModel: obj) ->
match objViewModel with
| :? ViewModel<obj, obj> as viewModel ->
setBindingContextsUntyped bindings viewModel
page.BindingContext <- objViewModel
| _ -> failwithf "unexpected type in pageInitUntyped: %A" (objViewModel.GetType())
let internal genViewName = let mutable c = 0 in fun () -> c <- c + 1; "StaticView"+string c
let internal apply (view: StaticView<_, _, _>) =
let page, bindings = view()
let name = genViewName()
name, page, bindings
let subPage (view1: StaticView<_, _, _>) =
let nm1, page1, bindings1 = apply view1
page1,
[ nm1 |> Binding.subView (pageInitUntyped page1 bindings1) id id bindings1 ]
let combo2 (view1: StaticView<_, _, _>) (view2: StaticView<_, _, _>) =
let nm1, page1, bindings1 = apply view1
let nm2, page2, bindings2 = apply view2
(page1, page2),
[ nm1 |> Binding.subView (pageInitUntyped page1 bindings1) (fun (a,_) -> a) Choice1Of2 bindings1
nm2 |> Binding.subView (pageInitUntyped page1 bindings2) (fun (_,a) -> a) Choice2Of2 bindings2 ]
let combo3 (view1: StaticView<_, _, _>) (view2: StaticView<_, _, _>) (view3: StaticView<_, _, _>) =
let nm1, page1, bindings1 = apply view1
let nm2, page2, bindings2 = apply view2
let nm3, page3, bindings3 = apply view3
(page1, page2, page3),
[ nm1 |> Binding.subView (pageInitUntyped page1 bindings1) (fun (a,_,_) -> a) Choice1Of3 bindings1
nm2 |> Binding.subView (pageInitUntyped page2 bindings2) (fun (_,a,_) -> a) Choice2Of3 bindings2
nm3 |> Binding.subView (pageInitUntyped page3 bindings3) (fun (_,_,a) -> a) Choice3Of3 bindings3 ]
let combo4 (view1: StaticView<_, _, _>) (view2: StaticView<_, _, _>) (view3: StaticView<_, _, _>) (view4: StaticView<_, _, _>) =
let nm1, page1, bindings1 = apply view1
let nm2, page2, bindings2 = apply view2
let nm3, page3, bindings3 = apply view3
let nm4, page4, bindings4 = apply view4
(page1, page2, page3, page4),
[ nm1 |> Binding.subView (pageInitUntyped page1 bindings1) (fun (a,_,_,_) -> a) Choice1Of4 bindings1
nm2 |> Binding.subView (pageInitUntyped page2 bindings2) (fun (_,a,_,_) -> a) Choice2Of4 bindings2
nm3 |> Binding.subView (pageInitUntyped page3 bindings3) (fun (_,_,a,_) -> a) Choice3Of4 bindings3
nm4 |> Binding.subView (pageInitUntyped page4 bindings4) (fun (_,_,_,a) -> a) Choice4Of4 bindings4 ]
[<RequireQualifiedAccess>]
module Program =
/// Start the program loop.
/// arg: argument to pass to the init() function.
/// program: program created with 'mkSimple' or 'mkProgram'.
let runOnGuiThreadWith (arg: 'arg) (program: Program<'arg, 'model, 'msg, 'view>) =
let (model,cmd) = program.init arg
let mutable state = model
let rec processMsg msg =
try
let (updatedModel,newCommands) = program.update msg state
program.setState updatedModel dispatch
newCommands |> List.iter (fun sub -> sub dispatch)
state <- updatedModel
with ex ->
//System.Diagnostics.Debugger.Log(ex.Message)
//System.Diagnostics.Debug.Fail(ex.Message)
System.Diagnostics.Debugger.Break()
program.onError ("Unable to process a message:", ex)
and dispatch msg = Device.BeginInvokeOnMainThread(fun () -> processMsg msg)
program.setState model dispatch
program.subscribe model
@ cmd |> List.iter (fun sub -> sub dispatch)
/// Start the dispatch loop with `unit` for the init() function.
let runOnGuiThread (program: Program<unit, 'model, 'msg, 'view>) = runOnGuiThreadWith () program
/// Starts the Elmish dispatch loop for the page with the given Elmish program
let _runStaticView debug (program: Program<_, _, _, _>) =
// Compute the view mappings once, on startup.
console.log "view: computing initial view with dummy model/dispatch"
let page,bindings = program.view Unchecked.defaultof<_> (fun _ -> failwith "do not call disaptch in the view")
let mutable lastModel = None
let setState model dispatch =
match lastModel with
| None ->
// Construct the binding context for the view model
let viewModel = ViewModel (model, dispatch, bindings, debug)
let viewData = StaticView.pageInit page None bindings viewModel model dispatch
lastModel <- Some (viewModel, viewData)
console.log "view: set data context"
| Some (viewModel, prevViewData) ->
let viewData = StaticView.pageUpdate page None model prevViewData dispatch
lastModel <- Some (viewModel, viewData)
viewModel.UpdateModel model
// Start Elmish dispatch loop
{ program with setState = setState }
|> runOnGuiThread
page
/// Starts the Elmish dispatch loop for the page with the given Elmish program
let _runDynamicView debug (program: Program<_, _, _, _>) =
// Compute the view mappings once, on startup.
console.log "view: computing initial page"
let page, bindings, contentf = program.view Unchecked.defaultof<_> (fun _ -> failwith "do not call disaptch in the view")
let mutable lastModel = None
let setState model dispatch =
match lastModel with
| None ->
// Construct the binding context for the view model
let viewModel = ViewModel (model, dispatch, bindings, debug)
let viewData = StaticView.pageInit page (Some contentf) bindings viewModel model dispatch
lastModel <- Some (viewModel, viewData)
console.log "view: set data context"
| Some (viewModel, prevViewData) ->
let viewData = StaticView.pageUpdate page (Some contentf) model prevViewData dispatch
lastModel <- Some (viewModel, viewData)
viewModel.UpdateModel model
// Start Elmish dispatch loop
{ program with setState = setState }
|> runOnGuiThread
page
/// Creates the view model for the given page and starts the Elmish dispatch loop for the matching program
let runDynamicView program = _runDynamicView false program
/// Creates the view model for the given page and starts the Elmish dispatch loop for the matching program
let runStaticView program = _runStaticView false program
/// Creates the view model for the given page and starts the Elmish dispatch loop for the matching program
let run program = runStaticView program
/// Creates the view model for the given page and starts the Elmish dispatch loop for the matching program
let runDebugDynamicView program = _runDynamicView true program
/// Creates the view model for the given page and starts the Elmish dispatch loop for the matching program
let runDebugStaticView program = _runStaticView true program
/// Creates the view model for the given page and starts the Elmish dispatch loop for the matching program
let runDebug program = runDebugStaticView program
let withNavigation (program: Program<_,_,_,_>) =
{ init = program.init
update = program.update
subscribe = program.subscribe
setState = program.setState
onError = program.onError
view = (fun m d ->
let page, bindings, navMap = program.view m d
console.log "view: setting global navigation map"
// TODO: modify the Elmish framework we use to remove this global state and pass it into all commands??
Nav.globalNavMap <- (navMap |> List.map (fun (tg, page) -> ((tg :> System.IComparable), page)) |> Map.ofList)
page, bindings )}
namespace Elmish.XamarinForms.DynamicViews
open Xamarin.Forms
open Elmish
open Elmish.XamarinForms
open Elmish.XamarinForms.DynamicViews
(*
[<AutoOpen>]
module GridHelpers =
open System.Runtime.CompilerServices
open System.Collections.Generic
open System.Windows.Input
type XamlElement with
/// Adjust the RowSpacing property in the visual element
member x.WithGridRowSpacing(value: double) = x.WithAttribute("GridRowSpacing", box (makeGridLength value))
/// Adjust the ColumnSpacing property in the visual element
member x.WithGridColumnSpacing(value: double) = x.WithAttribute("GridColumnSpacing", box (makeGridLength value))
/// Adjust the RowDefinitions property in the visual element
member x.WithGridRowDefinitions (value: IList<XamlElement>) = x.WithAttribute("GridRowDefinitions", box value)
/// Adjust the Column property in the visual element
member x.WithGridColumnDefinitions (value: IList<XamlElement>) = x.WithAttribute("GridColumnDefinitions", box value)
/// Adjust the Grid Row property in the visual element
member x.WithGridRow(value: int) = x.WithAttribute("GridRow", box value)
/// Adjust the Grid Column property in the visual element
member x.WithGridColumn(value: int) = x.WithAttribute("GridColumn", box value)
/// Adjust the Grid RowSpan property in the visual element
member x.WithGridRowSpan(value: int) = x.WithAttribute("GridRowSpan", box value)
/// Adjust the Grid ColumnSpan property in the visual element
member x.WithGridColumnSpan(value: int) = x.WithAttribute("GridColumnSpan", box value)
/// Try to get the Grid Row property in the visual element
member x.TryGridRow = match x.Attributes.TryFind("GridRow") with Some v -> Some(unbox<int>(v)) | None -> None
/// Try to get the Grid Column property in the visual element
member x.TryGridColumn = match x.Attributes.TryFind("GridColumn") with Some v -> Some(unbox<int>(v)) | None -> None
/// Try to get the Grid RowSpan property in the visual element
member x.TryGridRowSpan = match x.Attributes.TryFind("GridRowSpan") with Some v -> Some(unbox<int>(v)) | None -> None
/// Try to get the Grid ColumnSpan property in the visual element
member x.TryGridColumnSpan = match x.Attributes.TryFind("GridColumnSpan") with Some v -> Some(unbox<int>(v)) | None -> None
/// Try to get the Grid RowSpacing property in the visual element
member x.TryGridRowSpacing = match x.Attributes.TryFind("GridRowSpacing") with Some v -> Some(unbox<double>(v)) | None -> None
/// Try to get the Grid ColumnSpacing property in the visual element
member x.TryGridColumnSpacing = match x.Attributes.TryFind("GridColumnSpacing") with Some v -> Some(unbox<double>(v)) | None -> None
/// Get the RowDefinitions property in the visual element
member x.TryGridRowDefinitions = match x.Attributes.TryFind("GridRowDefinitions") with Some v -> Some(unbox<IList<XamlElement>>(v)) | None -> None
/// Get the ColumnDefinitions property in the visual element
member x.TryGridColumnDefinitions = match x.Attributes.TryFind("GridColumnDefinitions") with Some v -> Some(unbox<IList<XamlElement>>(v)) | None -> None
/// Create as a ColumnDefinition element
member x.CreateAsGridColumnDefinition () = x.Create() :?> ColumnDefinition
/// Create as a RowDefinition element
member x.CreateAsGridRowDefinition () = x.Create() :?> RowDefinition
/// Represents a ListViewDescription in the view desription
type Xaml with
static member Grid(?rowdefs: IList<XamlElement>, ?coldefs: IList<XamlElement>, ?children: IList<XamlElement>, ?rowSpacing: obj, ?columnSpacing: obj, ?horizontalOptions: Xamarin.Forms.LayoutOptions, ?verticalOptions: Xamarin.Forms.LayoutOptions, ?margin: Xamarin.Forms.Thickness, ?backgroundColor: Xamarin.Forms.Color, ?isVisible: bool, ?opacity: double, ?widthRequest: double, ?heightRequest: double, ?isEnabled: bool) =
let create () =
box (new Xamarin.Forms.Grid())
let apply (prevOpt: XamlElement option) (source: XamlElement) (targetObj:obj) =
let target = (targetObj :?> Xamarin.Forms.Grid)
match source.TryGridRowDefinitions with
| Some coll when coll <> null && coll.Count > 0 ->
if (coll = null || coll.Count = 0) then
match target.RowDefinitions with
| null -> ()
| coll -> coll.Clear()
else
// Remove the excess children
while (target.RowDefinitions.Count > coll.Count) do
target.RowDefinitions.RemoveAt(target.RowDefinitions.Count - 1)
// Count the existing children
let n = target.RowDefinitions.Count
// Adjust the existing children and create new children
for i in 0 .. n - 1 do
let newChild = coll.[i]
let prevChildOpt = match prevOpt with None -> None | Some prev -> match prev.TryChildren with None -> None | Some coll when i < coll.Count -> Some coll.[i] | _ -> None
if (match prevChildOpt with None -> true | Some prevChild -> not (obj.ReferenceEquals(prevChild, newChild))) then
let targetChild = target.Children.[i]
if (match prevChildOpt with None -> true | Some prevChild -> newChild.TargetType <> prevChild.TargetType) then
target.RowDefinitions.[i] <- newChild.CreateAsGridRowDefinition()
else
newChild.ApplyIncremental(prevChildOpt.Value, targetChild)
// Create the new children
for i in n .. coll.Count-1 do
target.RowDefinitions.Insert(i, coll.[i].CreateAsGridRowDefinition())
| _ -> ()
match source.TryGridColumnDefinitions with
| Some coll when coll <> null && coll.Count > 0 ->
if (coll = null || coll.Count = 0) then
match target.ColumnDefinitions with
| null -> ()
| coll -> coll.Clear()
else
// Remove the excess children
while (target.ColumnDefinitions.Count > coll.Count) do
target.ColumnDefinitions.RemoveAt(target.ColumnDefinitions.Count - 1)
// Count the existing children
let n = target.ColumnDefinitions.Count
// Adjust the existing children
for i in 0 .. n - 1 do
let newChild = coll.[i]
let prevChildOpt = match prevOpt with None -> None | Some prev -> match prev.TryChildren with None -> None | Some coll when i < coll.Count -> Some coll.[i] | _ -> None
if (match prevChildOpt with None -> true | Some prevChild -> not (obj.ReferenceEquals(prevChild, newChild))) then
let targetChild = target.Children.[i]
if (match prevChildOpt with None -> true | Some prevChild -> newChild.TargetType <> prevChild.TargetType) then
target.ColumnDefinitions.[i] <- newChild.CreateAsGridColumnDefinition()
else
newChild.ApplyIncremental(prevChildOpt.Value, targetChild)
// Create the new children
for i in n .. coll.Count-1 do
target.ColumnDefinitions.Insert(i, coll.[i].CreateAsGridColumnDefinition())
| _ -> ()
match source.TryChildren with
| Some coll when coll <> null && coll.Count > 0 ->
if (coll = null || coll.Count = 0) then
match target.Children with
| null -> ()
| children -> children.Clear()
else
// Remove the excess children
while (target.Children.Count > coll.Count) do
target.Children.RemoveAt(target.Children.Count - 1)
// Count the existing children
let n = target.Children.Count
// Adjust the existing children and create new children
for i in 0 .. coll.Count-1 do
let newChild = coll.[i]
let prevChildOpt = match prevOpt with None -> None | Some prev -> match prev.TryChildren with Some coll when i < coll.Count && i < n -> Some coll.[i] | _ -> None
let prevChildOpt, targetChild =
if (match prevChildOpt with None -> true | Some prevChild -> not (obj.ReferenceEquals(prevChild, newChild))) then
let mustCreate = (i >= n || match prevChildOpt with None -> true | Some prevChild -> newChild.TargetType <> prevChild.TargetType)
if mustCreate then
let targetChild = newChild.CreateAsView()
if i >= n then
target.Children.Insert(i, targetChild)
else
target.Children.[i] <- targetChild
None, targetChild
else
let targetChild = target.Children.[i]
newChild.ApplyIncremental(prevChildOpt.Value, targetChild)
prevChildOpt, targetChild
else
prevChildOpt, target.Children.[i]
// Adjust the attached properties
match (match prevChildOpt with None -> None | Some prevChild -> prevChild.TryGridRow), newChild.TryGridRow with
| Some prev, Some v when prev = v -> ()
| _, Some v -> Grid.SetRow(targetChild, v)
| _ -> ()
match (match prevChildOpt with None -> None | Some prevChild -> prevChild.TryGridColumn), newChild.TryGridColumn with
| Some prev, Some v when prev = v -> ()
| _, Some v -> Grid.SetColumn(targetChild, v)
| _ -> ()
match (match prevChildOpt with None -> None | Some prevChild -> prevChild.TryGridRowSpan), newChild.TryGridRowSpan with
| Some prev, Some v when prev = v -> ()
| _, Some v -> Grid.SetRowSpan(targetChild, v)
| _ -> ()
match (match prevChildOpt with None -> None | Some prevChild -> prevChild.TryGridColumnSpan), newChild.TryGridColumnSpan with
| Some prev, Some v when prev = v -> ()
| _, Some v -> Grid.SetColumnSpan(targetChild, v)
| _ -> ()
| _ -> ()
let prevRowSpacing = match prevOpt with Some prev -> prev.TryGridRowSpacing | _ -> None
match prevRowSpacing, source.TryGridRowSpacing with
| Some prev, Some v when prev = v -> ()
| _, Some v -> target.RowSpacing <- v
| _, None -> ()
let prevColumnSpacing = match prevOpt with Some prev -> prev.TryGridColumnSpacing | _ -> None
match prevColumnSpacing, source.TryGridColumnSpacing with
| Some prev, Some v when prev = v -> ()
| _, Some v -> target.ColumnSpacing <- v
| _, None -> ()
let attribs = [|
match children with None -> () | Some v -> yield ("Children", box v)
match rowSpacing with None -> () | Some v -> yield ("GridRowSpacing", box (makeGridLength v))
match columnSpacing with None -> () | Some v -> yield ("GridColumnSpacing", box (makeGridLength v))
match rowdefs with None -> () | Some v -> yield ("GridRowDefinitions", box v)
match coldefs with None -> () | Some v -> yield ("GridColumnDefinitions", box v)
|]
Xaml.Layout().Inherit(typeof<Xamarin.Forms.Grid>, create, apply, attribs)
let withRowSpacing m (x: XamlElement) = x.WithGridRowSpacing m
let rowSpacing m x = withRowSpacing m x
let withColumnSpacing m (x: XamlElement) = x.WithGridColumnSpacing m
let columnSpacing m (x: XamlElement) = withColumnSpacing m x
let withGridRow row (el: XamlElement) = el.WithGridRow(row)
let gridRow row (el: XamlElement) = el.WithGridRow(row)
let withGridColumn col (el: XamlElement) = el.WithGridColumn(col)
let gridColumn col (el: XamlElement) = el.WithGridColumn(col)
let withGridRowSpan rowspan (el: XamlElement) = el.WithGridRowSpan(rowspan)
let gridRowSpan rowspan (el: XamlElement) = el.WithGridRowSpan(rowspan)
let withGridColumnSpan colspan (el: XamlElement) = el.WithGridColumnSpan(colspan)
let gridColumnSpan colspan (el: XamlElement) = el.WithGridColumnSpan(colspan)
*)
[<AutoOpen>]
module SimplerHelpers =
open System.Runtime.CompilerServices
open System.Collections.Generic
open System.Windows.Input
let rowdef h = Xaml.RowDefinition(height=makeGridLength h)
let coldef h = Xaml.ColumnDefinition(width=makeGridLength h)
let rows rds (els: XamlElement list) =
let children = els |> List.mapi (fun i x -> x.GridRow i)
Xaml.Grid(rowdefs=rds, children=children)
let cols cds (els: XamlElement list) =
let children = els |> List.mapi (fun i x -> x.GridColumn i)
Xaml.Grid(coldefs=cds, children=children)
// Helper page for the TicTacToe sample
// Need to generlize the HeightRequest phase of the XF content digestion process...
type HelperPage(?viewAllocatedSizeFixup) as self =
inherit ContentPage()
do Xamarin.Forms.PlatformConfiguration.iOSSpecific.Page.SetUseSafeArea(self, true)
// painful.... It is unfortunately not possible to simpy recreate the whole
// view here, you have to mutate the content in-place.
override this.OnSizeAllocated(width, height) =
base.OnSizeAllocated(width, height)
match viewAllocatedSizeFixup with
| Some f -> f self.Content (width, height)
| None -> ()

Просмотреть файл

@ -0,0 +1,40 @@
// Copyright 2018 Elmish.XamarinForms contributors. See LICENSE.md for license.
namespace Elmish.XamarinForms.DynamicViews
open Xamarin.Forms
open Elmish.XamarinForms
open Elmish.XamarinForms.DynamicViews
[<AutoOpen>]
module SimplerHelpers =
open System.Runtime.CompilerServices
open System.Collections.Generic
open System.Windows.Input
let rowdef h = Xaml.RowDefinition(height=makeGridLength h)
let coldef h = Xaml.ColumnDefinition(width=makeGridLength h)
let rows rds (els: XamlElement list) =
let children = els |> List.mapi (fun i x -> x.GridRow i)
Xaml.Grid(rowdefs=rds, children=children)
let cols cds (els: XamlElement list) =
let children = els |> List.mapi (fun i x -> x.GridColumn i)
Xaml.Grid(coldefs=cds, children=children)
// Helper page for the TicTacToe sample
// Need to generlize the HeightRequest phase of the XF content digestion process...
type HelperPage(?viewAllocatedSizeFixup) as self =
inherit ContentPage()
do Xamarin.Forms.PlatformConfiguration.iOSSpecific.Page.SetUseSafeArea(self, true)
// painful.... It is unfortunately not possible to simpy recreate the whole
// view here, you have to mutate the content in-place.
override this.OnSizeAllocated(width, height) =
base.OnSizeAllocated(width, height)
match viewAllocatedSizeFixup with
| Some f -> f self.Content (width, height)
| None -> ()

Просмотреть файл

@ -6,19 +6,11 @@
<Compile Include="AssemblyInfo.fs" />
<Compile Include="DynamicXamlConverters.fs" />
<Compile Include="DynamicXaml.fs" />
<Compile Include="FableStub.fs" />
<Compile Include="..\paket-files\neutral\fable-elmish\elmish\src\cmd.fs">
<Paket>True</Paket>
<Link>elmish/src/cmd.fs</Link>
</Compile>
<Compile Include="..\paket-files\neutral\fable-elmish\elmish\src\program.fs">
<Paket>True</Paket>
<Link>elmish/src/program.fs</Link>
</Compile>
<Compile Include="Cmd.fs" />
<Compile Include="Binding.fs" />
<Compile Include="ViewModel.fs" />
<Compile Include="Combinators.fs" />
<Compile Include="ElmishCmd.fs" />
<Compile Include="StaticXamlBinding.fs" />
<Compile Include="StaticXamlViewModel.fs" />
<Compile Include="ElmishProgram.fs" />
<Compile Include="DynamicViewHelpers.fs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="FSharp.Core" Version="4.3.3" />

Просмотреть файл

@ -0,0 +1,55 @@
// Copyright 2018 Elmish and Elmish.XamarinForms contributors. See LICENSE.md for license.
namespace Elmish.XamarinForms
open System
open System.Diagnostics
open FSharp.Control
/// Dispatch - feed new message into the processing loop
type Dispatch<'msg> = 'msg -> unit
/// Subscription - return immediately, but may schedule dispatch of a message at any time
type Sub<'msg> = Dispatch<'msg> -> unit
/// Cmd - container for subscriptions that may produce messages
type Cmd<'msg> = Sub<'msg> list
/// Cmd module for creating and manipulating commands
[<RequireQualifiedAccess>]
module Cmd =
/// None - no commands, also known as `[]`
let none : Cmd<'msg> =
[]
/// Command to issue a specific message
let ofMsg (msg:'msg) : Cmd<'msg> =
[fun dispatch -> dispatch msg]
/// When emitting the message, map to another type
let map (f: 'a -> 'msg) (cmd: Cmd<'a>) : Cmd<'msg> =
cmd |> List.map (fun g -> (fun dispatch -> f >> dispatch) >> g)
/// Aggregate multiple commands
let batch (cmds: #seq<Cmd<'msg>>) : Cmd<'msg> =
cmds |> List.concat
/// Command to call the subscriber
let ofSub (sub: Sub<'msg>) : Cmd<'msg> =
[sub]
let dispatch d (cmd: Cmd<_>) = for sub in cmd do sub d
let ofAsyncMsg (p: Async<'msg>) : Cmd<_> =
[ fun dispatch -> async { let! msg = p in dispatch p } |> Async.StartImmediate ]
let ofAsyncMsgs p : Cmd<_> =
[ fun dispatch -> p |> AsyncSeq.iter dispatch |> Async.StartImmediate ]
type CmdBuilder() =
inherit AsyncSeq.AsyncSeqBuilder()
member x.Run(p: AsyncSeq<_>) = ofAsyncMsgs p
[<AutoOpen>]
module CommandBuilder =
let cmd = Cmd.CmdBuilder()

Просмотреть файл

@ -0,0 +1,417 @@
// Copyright 2018 Elmish.XamarinForms contributors. See LICENSE.md for license.
namespace Elmish.XamarinForms
open System
open System.Diagnostics
open Elmish.XamarinForms
open Elmish.XamarinForms.StaticViews
open Elmish.XamarinForms.DynamicViews
open Xamarin.Forms
/// Represents a model when you don't have a model. A Clayton's model.
type NoModel =
| NoModel
type Update<'model, 'msg> = 'msg -> 'model -> 'model * Cmd<'msg>
type Update<'model, 'msg, 'extmsg> = 'msg -> 'model -> 'model * Cmd<'msg> * 'extmsg
type StaticView<'model, 'msg, 'page> = unit -> 'page * ViewBindings<'model, 'msg>
type DynamicView<'model, 'msg, 'page> = unit -> 'page * ('model -> 'msg -> Xamarin.Forms.View)
[<AutoOpen>]
module Values =
let NoCmd<'a> : Cmd<'a> = Cmd.none
let mutable currentPage : Page = null
[<RequireQualifiedAccess>]
module Nav =
// TODO: modify the Elmish framework we use to remove this global state and pass it into all commands??
let mutable globalNavMap : Map<System.IComparable, Page> = Map.empty
/// Push new location into history and navigate there
let push (fromPageTag: ('navTarget :> System.IComparable)) (toPageTag: ('navTarget :> System.IComparable)) : Cmd<_> =
[ fun _ ->
let fromPage = globalNavMap.[fromPageTag]
let toPage = globalNavMap.[toPageTag]
let nav = fromPage.Navigation
nav.PushAsync toPage |> ignore ]
/// Push new location into history and navigate there
let pushModal (fromPageTag: ('navTarget :> System.IComparable)) (toPageTag: ('navTarget :> System.IComparable)) : Cmd<_> =
[ fun _ ->
let fromPage = globalNavMap.[fromPageTag]
let toPage = globalNavMap.[toPageTag]
let nav = fromPage.Navigation
nav.PushModalAsync toPage |> ignore ]
let popToRoot (fromPageTag: ('navTarget :> System.IComparable)) : Cmd<_> =
[ fun _ ->
let fromPage = globalNavMap.[fromPageTag]
let nav = fromPage.Navigation
nav.PopToRootAsync() |> ignore ]
let popModal (fromPageTag: ('navTarget :> System.IComparable)) : Cmd<_> =
[ fun _ ->
let fromPage = globalNavMap.[fromPageTag]
let nav = fromPage.Navigation
nav.PopModalAsync() |> ignore ]
let pop (fromPageTag: ('navTarget :> System.IComparable)) : Cmd<_> =
[ fun _ ->
let fromPage = globalNavMap.[fromPageTag]
let nav = fromPage.Navigation
nav.PopAsync() |> ignore ]
[<RequireQualifiedAccess>]
module Init =
let combo2 init1 init2 () =
let model1 = init1()
let model2 = init2()
(model1, model2)
let combo3 init1 init2 init3 () =
let model1 = init1()
let model2 = init2()
let model3 = init3()
(model1, model2, model3)
let combo4 init1 init2 init3 init4 () =
let model1 = init1()
let model2 = init2()
let model3 = init3()
let model4 = init4()
(model1, model2, model3, model4)
let combo5 init1 init2 init3 init4 init5 () =
let model1 = init1()
let model2 = init2()
let model3 = init3()
let model4 = init4()
let model5 = init5()
(model1, model2, model3, model4, model5)
[<RequireQualifiedAccess>]
module InitCmd =
let combo2 init1 init2 () =
let model1, cmd1 = init1()
let model2, cmd2 = init2()
(model1, model2), Cmd.batch [cmd1; cmd2]
let combo3 init1 init2 init3 () =
let model1, cmd1 = init1()
let model2, cmd2 = init2()
let model3, cmd3 = init3()
(model1, model2, model3), Cmd.batch [cmd1; cmd2; cmd3]
let combo4 init1 init2 init3 init4 () =
let model1, cmd1 = init1()
let model2, cmd2 = init2()
let model3, cmd3 = init3()
let model4, cmd4 = init4()
(model1, model2, model3, model4), Cmd.batch [cmd1; cmd2; cmd3; cmd4]
let combo5 init1 init2 init3 init4 init5 () =
let model1, cmd1 = init1()
let model2, cmd2 = init2()
let model3, cmd3 = init3()
let model4, cmd4 = init4()
let model5, cmd5 = init5()
(model1, model2, model3, model4, model5), Cmd.batch [cmd1; cmd2; cmd3; cmd4; cmd5]
[<RequireQualifiedAccess>]
module Update =
let combo2 (update1: Update<_, _, _>) (update2: Update<_, _, _>) : Update<_,_,_> = fun msg (model1, model2) ->
match msg with
| Choice1Of2 msg1 -> let newModel, cmds, extmsg = update1 msg1 model1 in (newModel, model2), Cmd.map Choice1Of2 cmds, extmsg
| Choice2Of2 msg2 -> let newModel, cmds, extmsg = update2 msg2 model2 in (model1, newModel), Cmd.map Choice2Of2 cmds, extmsg
let combo3 (update1: Update<_, _, _>) (update2: Update<_, _, _>) (update3: Update<_, _, _>) : Update<_,_,_> = fun msg (model1, model2, model3) ->
match msg with
| Choice1Of3 msg1 -> let newModel, cmds, extmsg = update1 msg1 model1 in (newModel, model2, model3), Cmd.map Choice1Of3 cmds, extmsg
| Choice2Of3 msg2 -> let newModel, cmds, extmsg = update2 msg2 model2 in (model1, newModel, model3), Cmd.map Choice2Of3 cmds, extmsg
| Choice3Of3 msg3 -> let newModel, cmds, extmsg = update3 msg3 model3 in (model1, model2, newModel), Cmd.map Choice3Of3 cmds, extmsg
let combo4 (update1: Update<_, _, _>) (update2: Update<_, _, _>) (update3: Update<_, _, _>) (update4: Update<_, _, _>) : Update<_,_,_> = fun msg (model1, model2, model3, model4) ->
match msg with
| Choice1Of4 msg1 -> let newModel, cmds, extmsg = update1 msg1 model1 in (newModel, model2, model3, model4), Cmd.map Choice1Of4 cmds, extmsg
| Choice2Of4 msg2 -> let newModel, cmds, extmsg = update2 msg2 model2 in (model1, newModel, model3, model4), Cmd.map Choice2Of4 cmds, extmsg
| Choice3Of4 msg3 -> let newModel, cmds, extmsg = update3 msg3 model3 in (model1, model2, newModel, model4), Cmd.map Choice3Of4 cmds, extmsg
| Choice4Of4 msg4 -> let newModel, cmds, extmsg = update4 msg4 model4 in (model1, model2, model3, newModel), Cmd.map Choice4Of4 cmds, extmsg
let combo5 (update1: Update<_, _, _>) (update2: Update<_, _, _>) (update3: Update<_, _, _>) (update4: Update<_, _, _>) (update5: Update<_, _, _>) : Update<_,_,_> = fun msg (model1, model2, model3, model4, model5) ->
match msg with
| Choice1Of5 msg1 -> let newModel, cmds, extmsg = update1 msg1 model1 in (newModel, model2, model3, model4, model5), Cmd.map Choice1Of5 cmds, extmsg
| Choice2Of5 msg2 -> let newModel, cmds, extmsg = update2 msg2 model2 in (model1, newModel, model3, model4, model5), Cmd.map Choice2Of5 cmds, extmsg
| Choice3Of5 msg3 -> let newModel, cmds, extmsg = update3 msg3 model3 in (model1, model2, newModel, model4, model5), Cmd.map Choice3Of5 cmds, extmsg
| Choice4Of5 msg4 -> let newModel, cmds, extmsg = update4 msg4 model4 in (model1, model2, model3, newModel, model5), Cmd.map Choice4Of5 cmds, extmsg
| Choice5Of5 msg5 -> let newModel, cmds, extmsg = update5 msg5 model5 in (model1, model2, model3, model4, newModel), Cmd.map Choice5Of5 cmds, extmsg
/// Reconcile external messages by turning them into changes in the composed model and/or commands
let reconcile f (update: Update<'model,'msg,'extmsg>) : Update<'model,'msg> = fun msg model ->
let newModel, cmds, extmsg = update msg model
let newModel2, cmds2 = f extmsg newModel
newModel2, Cmd.batch [cmds; cmds2]
[<RequireQualifiedAccess>]
module StaticView =
let internal setBindingContextsUntyped (bindings: ViewBindings<'model, 'msg>) (viewModel: StaticViewModel<obj, obj>) =
for (bindingName, binding) in bindings do
match binding with
| BindSubModel (ViewSubModel (initf, _, _, _, _)) ->
Trace.WriteLine (sprintf "view: seting data context for %s" bindingName)
let subModel = viewModel.[bindingName]
initf subModel
| _ -> ()
let internal setBindingContexts (bindings: ViewBindings<'model, 'msg>) (viewModel: StaticViewModel<'model, 'msg>) =
for (bindingName, binding) in bindings do
match binding with
| BindSubModel (ViewSubModel (initf, _, _, _, _)) ->
Trace.WriteLine (sprintf "view: seting data context for %s" bindingName)
let subModel = viewModel.[bindingName]
initf subModel
| _ -> ()
let internal staticPageInitUntyped (page: ContentPage) (bindings: ViewBindings<'model, 'msg>) =
fun (objViewModel: obj) ->
match objViewModel with
| :? StaticViewModel<obj, obj> as viewModel ->
setBindingContextsUntyped bindings viewModel
page.BindingContext <- objViewModel
| _ -> failwithf "unexpected type in staticPageInitUntyped: %A" (objViewModel.GetType())
let internal genViewName = let mutable c = 0 in fun () -> c <- c + 1; "View"+string c
let internal apply (view: StaticView<_, _, _>) =
let page, bindings = view()
let name = genViewName()
name, page, bindings
let subPage (view1: StaticView<_, _, _>) =
let nm1, page1, bindings1 = apply view1
page1,
[ nm1 |> Binding.subView (staticPageInitUntyped page1 bindings1) id id bindings1 ]
let combo2 (view1: StaticView<_, _, _>) (view2: StaticView<_, _, _>) =
let nm1, page1, bindings1 = apply view1
let nm2, page2, bindings2 = apply view2
(page1, page2),
[ nm1 |> Binding.subView (staticPageInitUntyped page1 bindings1) (fun (a,_) -> a) Choice1Of2 bindings1
nm2 |> Binding.subView (staticPageInitUntyped page1 bindings2) (fun (_,a) -> a) Choice2Of2 bindings2 ]
let combo3 (view1: StaticView<_, _, _>) (view2: StaticView<_, _, _>) (view3: StaticView<_, _, _>) =
let nm1, page1, bindings1 = apply view1
let nm2, page2, bindings2 = apply view2
let nm3, page3, bindings3 = apply view3
(page1, page2, page3),
[ nm1 |> Binding.subView (staticPageInitUntyped page1 bindings1) (fun (a,_,_) -> a) Choice1Of3 bindings1
nm2 |> Binding.subView (staticPageInitUntyped page2 bindings2) (fun (_,a,_) -> a) Choice2Of3 bindings2
nm3 |> Binding.subView (staticPageInitUntyped page3 bindings3) (fun (_,_,a) -> a) Choice3Of3 bindings3 ]
let combo4 (view1: StaticView<_, _, _>) (view2: StaticView<_, _, _>) (view3: StaticView<_, _, _>) (view4: StaticView<_, _, _>) =
let nm1, page1, bindings1 = apply view1
let nm2, page2, bindings2 = apply view2
let nm3, page3, bindings3 = apply view3
let nm4, page4, bindings4 = apply view4
(page1, page2, page3, page4),
[ nm1 |> Binding.subView (staticPageInitUntyped page1 bindings1) (fun (a,_,_,_) -> a) Choice1Of4 bindings1
nm2 |> Binding.subView (staticPageInitUntyped page2 bindings2) (fun (_,a,_,_) -> a) Choice2Of4 bindings2
nm3 |> Binding.subView (staticPageInitUntyped page3 bindings3) (fun (_,_,a,_) -> a) Choice3Of4 bindings3
nm4 |> Binding.subView (staticPageInitUntyped page4 bindings4) (fun (_,_,_,a) -> a) Choice4Of4 bindings4 ]
/// Program type captures various aspects of program behavior
type Program<'model, 'msg, 'view> =
{ init : unit -> 'model * Cmd<'msg>
update : 'msg -> 'model -> 'model * Cmd<'msg>
subscribe : 'model -> Cmd<'msg>
view : 'view
onError : (string*exn) -> unit }
/// Program module - functions to manipulate program instances
[<RequireQualifiedAccess>]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Program =
let internal onError (text: string, ex: exn) =
Trace.WriteLine (sprintf "%s: %A" text ex)
/// Typical program, new commands are produced by `init` and `update` along with the new state.
let mkProgram init update view =
{ init = init
update = update
view = view
subscribe = fun _ -> Cmd.none
onError = onError }
/// Simple program that produces only new state with `init` and `update`.
let mkSimple init update view = mkProgram (fun arg -> init arg, Cmd.none) (fun msg model -> update msg model, Cmd.none) view
/// Subscribe to external source of events.
/// The subscription is called once - with the initial model, but can dispatch new messages at any time.
let withSubscription (subscribe : 'model -> Cmd<'msg>) (program: Program<'model, 'msg, 'view>) =
let sub model =
Cmd.batch [ program.subscribe model
subscribe model ]
{ program with subscribe = sub }
/// Trace all the updates to the console
let withConsoleTrace (program: Program<'model, 'msg, 'view>) =
let traceInit () =
let initModel,cmd = program.init ()
Console.WriteLine (sprintf "Initial state: %A" initModel)
initModel,cmd
let traceUpdate msg model =
Console.WriteLine (sprintf "New message: %A" msg)
let newModel,cmd = program.update msg model
Console.WriteLine (sprintf "Updated state: %A" newModel)
newModel,cmd
{ program with
init = traceInit
update = traceUpdate }
/// Trace all the messages as they update the model
let withTrace trace (program: Program<'model, 'msg, 'view>) =
{ program
with update = fun msg model -> trace msg model; program.update msg model}
/// Handle dispatch loop exceptions
let withErrorHandler onError (program: Program<'model, 'msg, 'view>) =
{ program
with onError = onError }
/// Starts the Elmish dispatch loop for the page with the given Elmish program
let _run debug (program: Program<_, _, _>) =
Trace.WriteLine "run: computing initial model"
// Get the initial model
let (model,cmd) = program.init ()
let mutable lastModel = model
let mutable lastViewData = None
let initialMessages = ResizeArray<_>()
let mutable dispatchImpl = (fun msg -> initialMessages.Add(msg))
let dispatch msg = dispatchImpl msg
Trace.WriteLine "run: computing static components of view"
// Extract the static content from the view
let viewInfo = program.view ()
// If the view is dynamic, create the initial page
let viewInfo =
match viewInfo with
| Choice1Of2 (mainPage, bindings) -> Choice1Of2 (mainPage, bindings)
| Choice2Of2 (contentf: _ -> _ -> XamlElement) ->
let pageDescription = contentf model dispatch
let mainPage = pageDescription.CreateAsPage()
Choice2Of2 (pageDescription, mainPage, contentf)
// We need a mainPage to return
let mainPage =
match viewInfo with
| Choice1Of2 (mainPage, bindings) -> mainPage
| Choice2Of2 (_, mainPage, _) -> mainPage
// Start Elmish dispatch loop
let rec processMsg msg =
try
let (updatedModel,newCommands) = program.update msg lastModel
updateView updatedModel
newCommands |> List.iter (fun sub -> sub dispatch)
lastModel <- updatedModel
with ex ->
//System.Diagnostics.Debugger.Log(ex.Message)
//System.Diagnostics.Debug.Fail(ex.Message)
System.Diagnostics.Debugger.Break()
program.onError ("Unable to process a message:", ex)
and updateView model =
match lastViewData with
| None ->
// Construct the binding context for the view model
let viewData =
match viewInfo with
| Choice1Of2 (mainPage, bindings) ->
let viewModel = StaticViewModel (model, dispatch, bindings, debug)
StaticView.setBindingContexts bindings viewModel
mainPage.BindingContext <- box viewModel
Choice1Of2 (mainPage, bindings, viewModel)
| Choice2Of2 (pageDescription, mainPage, contentf) ->
Choice2Of2 (pageDescription, mainPage, contentf)
lastViewData <- Some viewData
Trace.WriteLine "view: set data context"
| Some prevViewData ->
let viewData =
match prevViewData with
| Choice1Of2 (page, bindings, viewModel) ->
viewModel.UpdateModel model
Choice1Of2 (page, bindings, viewModel)
| Choice2Of2 (prevPageDescription, page, contentf) ->
let newPageDescription: XamlElement = contentf model dispatch
newPageDescription.ApplyIncremental (prevPageDescription, page)
Choice2Of2 (newPageDescription, page, contentf)
| _ -> failwith "unreachable"
lastViewData <- Some viewData
let initialMsgs = initialMessages.ToArray()
initialMessages.Clear()
dispatchImpl <- (fun msg -> Device.BeginInvokeOnMainThread(fun () -> processMsg msg))
Trace.WriteLine "updating the initial view"
updateView model
Trace.WriteLine "dispatching initial commands"
for sub in (program.subscribe model @ cmd) do
sub dispatch
for initialMsg in initialMsgs do
dispatch initialMsg
mainPage
/// Creates the view model for the given page and starts the Elmish dispatch loop for the matching program
let run program = _run false program
/// Creates the view model for the given page and starts the Elmish dispatch loop for the matching program
let runDebug program = _run true program
let withNavigation (program: Program<_,_,_>) =
{ init = program.init
update = program.update
subscribe = program.subscribe
onError = program.onError
view = (fun () ->
let page, contents, navMap = program.view ()
Trace.WriteLine "view: setting global navigation map"
// TODO: modify the Elmish framework we use to remove this global state and pass it into all commands??
Nav.globalNavMap <- (navMap |> List.map (fun (tg, page) -> ((tg :> System.IComparable), page)) |> Map.ofList)
page, contents )}
let withStaticView (program: Program<_,_,_>) =
{ init = program.init
update = program.update
subscribe = program.subscribe
onError = program.onError
view = (fun () ->
let page, bindings = program.view ()
Choice1Of2 ((page :> Page), bindings)) }
let withDynamicView (program: Program<_,_,_>) =
{ init = program.init
update = program.update
subscribe = program.subscribe
onError = program.onError
view = (fun () -> Choice2Of2 program.view) }

Просмотреть файл

@ -1,39 +0,0 @@
// Copyright 2018 Elmish.XamarinForms contributors. See LICENSE.md for license.
[<AutoOpen>]
module Fable
[<AutoOpen>]
module PowerPack = ()
[<AutoOpen>]
module Core =
[<AutoOpen>]
module JsInterop = ()
[<AutoOpen>]
module Import =
[<AutoOpen>]
module Browser =
[<AutoOpen>]
type console =
[<System.Diagnostics.Conditional("DEBUG")>]
static member error (str, ex) = sprintf "%s: %O" str ex |> System.Console.WriteLine
[<System.Diagnostics.Conditional("DEBUG")>]
static member log (o: string) = sprintf "%s -- %A" (System.DateTime.Now.ToString("o")) o |> System.Console.WriteLine
[<System.Diagnostics.Conditional("DEBUG")>]
static member log (o: string, v:obj) = sprintf "%s -- %s %A" (System.DateTime.Now.ToString("o")) o v |> System.Console.WriteLine
let toJson o = o
[<AutoOpen>]
module JS =
[<AutoOpen>]
module JSON =
let parse str = str
type Promise() = class end
type Promise<'T>() =
inherit Promise()
with
static member map _ = failwith "Promise not supported"
static member catch _ = failwith "Promise not supported"

Просмотреть файл

@ -1,9 +1,9 @@
// Copyright 2018 Elmish.XamarinForms contributors. See LICENSE.md for license.
namespace Elmish.XamarinForms
namespace Elmish.XamarinForms.StaticViews
open System
open Xamarin.Forms
open Elmish
open Elmish.XamarinForms
type internal Getter<'model> =
'model -> obj

Просмотреть файл

@ -1,24 +1,25 @@
// Copyright 2018 Elmish.XamarinForms contributors. See LICENSE.md for license.
namespace Elmish.XamarinForms
namespace Elmish.XamarinForms.StaticViews
open System
open System.Collections.Generic
open System.ComponentModel
open System.Diagnostics
open Xamarin.Forms
open Elmish
open Elmish.XamarinForms
/// The internal representation of a binding in the ViewModel
/// The internal representation of a binding in the ViewModel for static Xaml
type internal PropertyBinding<'model, 'msg> =
| Get of Getter<'model>
| Set of Setter<'model, 'msg>
| GetSet of Getter<'model> * Setter<'model, 'msg>
| GetSetValidate of Getter<'model> * ValidSetter<'model, 'msg>
| Cmd of Xamarin.Forms.Command
| SubModel of ('model -> obj) * (obj -> 'msg) * ViewModel<obj, obj>
| SubModel of ('model -> obj) * (obj -> 'msg) * StaticViewModel<obj, obj>
| Map of Getter<'model> * (obj -> obj)
and ViewModel<'model, 'msg>(m: 'model, dispatch: 'msg -> unit, propMap: ViewBindings<'model, 'msg>, debug: bool) as self =
and StaticViewModel<'model, 'msg>(m: 'model, dispatch: 'msg -> unit, propMap: ViewBindings<'model, 'msg>, debug: bool) as self =
inherit System.Dynamic.DynamicObject()
let props = new Dictionary<string, PropertyBinding<'model, 'msg>>()
@ -33,7 +34,7 @@ and ViewModel<'model, 'msg>(m: 'model, dispatch: 'msg -> unit, propMap: ViewBind
// For INotifyPropertyChanged
let propertyChanged = Event<PropertyChangedEventHandler, PropertyChangedEventArgs> ()
let notifyPropertyChanged name =
if debug then console.log (sprintf "notifyPropertyChanged %s" name)
if debug then Trace.WriteLine (sprintf "notifyPropertyChanged %s" name)
let key = "Item[" + name + "]"
propertyChanged.Trigger(self, PropertyChangedEventArgs key)
@ -50,17 +51,17 @@ and ViewModel<'model, 'msg>(m: 'model, dispatch: 'msg -> unit, propMap: ViewBind
let toCommand name (exec, canExec) =
let execute =
Action<obj> (fun cmdParameter ->
if debug then console.log (sprintf "view: execute cmd %s" name)
if debug then Trace.WriteLine (sprintf "view: execute cmd %s" name)
let msg =
try exec cmdParameter model
with exn ->
if debug then console.log (sprintf "view: execute cmd %s raised exception:\n%s" name (exn.ToString()))
if debug then Trace.WriteLine (sprintf "view: execute cmd %s raised exception:\n%s" name (exn.ToString()))
reraise()
dispatch msg)
let canExecute =
Func<obj, bool>(fun cmdParameter ->
if debug then console.log (sprintf "view: checking if cmd %s can execute" name)
if debug then Trace.WriteLine (sprintf "view: checking if cmd %s can execute" name)
canExec cmdParameter model)
Xamarin.Forms.Command (execute, canExecute)
@ -73,7 +74,7 @@ and ViewModel<'model, 'msg>(m: 'model, dispatch: 'msg -> unit, propMap: ViewBind
| BindTwoWay (getter, setter) -> name, GetSet (getter, setter)
| BindTwoWayValidation (getter, setter) -> name, GetSetValidate (getter, setter)
| BindCmd (exec, canExec) -> name, Cmd (toCommand name (exec, canExec))
| BindSubModel (ViewSubModel (_, subName, getter, toMsg, propMap)) -> name, SubModel (getter, toMsg, ViewModel<obj, obj>(getter model, toMsg >> dispatch, propMap, debug))
| BindSubModel (ViewSubModel (_, subName, getter, toMsg, propMap)) -> name, SubModel (getter, toMsg, StaticViewModel<obj, obj>(getter model, toMsg >> dispatch, propMap, debug))
| BindMap (getter, mapper) -> name, Map (getter, mapper)
do propMap |> List.map convert |> List.iter props.Add
@ -89,7 +90,7 @@ and ViewModel<'model, 'msg>(m: 'model, dispatch: 'msg -> unit, propMap: ViewBind
member __.ErrorsChanged = errorsChanged.Publish
member __.HasErrors = errors.Count > 0
member __.GetErrors propName =
if debug then console.log (sprintf "Getting errors for %s" propName)
if debug then Trace.WriteLine (sprintf "Getting errors for %s" propName)
let results =
match errors.TryGetValue propName with
| true, errs -> errs
@ -99,8 +100,8 @@ and ViewModel<'model, 'msg>(m: 'model, dispatch: 'msg -> unit, propMap: ViewBind
/// Used internally to update the model. Only properties that have changed are updated.
member __.UpdateModel (other: 'model) : unit =
if Object.ReferenceEquals (model, other) then
if debug then console.log (sprintf "...Skipping update because model is reference-identical")
//if debug then console.log (sprintf "UpdateModel %+A" (props.Keys |> Seq.toArray))
if debug then Trace.WriteLine (sprintf "...Skipping update because model is reference-identical")
//if debug then Trace.WriteLine (sprintf "UpdateModel %+A" (props.Keys |> Seq.toArray))
let propDiff name prop =
match prop with
| Get getter
@ -143,15 +144,15 @@ and ViewModel<'model, 'msg>(m: 'model, dispatch: 'msg -> unit, propMap: ViewBind
| Map (getter, mapper) -> getter model |> mapper
| Set setter -> invalidOp (sprintf "Prop Binding Not Settable: %s" name)
if debug then console.log (sprintf "view: got %s = %+A" name value)
if debug then Trace.WriteLine (sprintf "view: got %s = %+A" name value)
value
else
if debug then console.log (sprintf "view: failed to get property %s" name)
if debug then Trace.WriteLine (sprintf "view: failed to get property %s" name)
invalidOp (sprintf "Prop Binding Not Set: %s" name)
and set (name : string) (value : obj) : unit =
if debug then console.log (sprintf "view: set %s to %+A" name value)
if debug then Trace.WriteLine (sprintf "view: set %s to %+A" name value)
if props.ContainsKey name then
@ -177,16 +178,16 @@ and ViewModel<'model, 'msg>(m: 'model, dispatch: 'msg -> unit, propMap: ViewBind
| false, _ -> errors.Add(name, [err])
errorsChanged()
| _ ->
if debug then console.log (sprintf "view: failed to set read-only property %s" name)
if debug then Trace.WriteLine (sprintf "view: failed to set read-only property %s" name)
invalidOp "Unable to set read-only member"
else
if debug then console.log (sprintf "view: failed to set unbound property %s" name)
if debug then Trace.WriteLine (sprintf "view: failed to set unbound property %s" name)
invalidOp (sprintf "Prop Binding Not Set: %s" name)
/// Used by the view to try to get values
override this.TryGetMember (binder, result) =
if debug then console.log (sprintf "view: TryGetMember %s" binder.Name)
if debug then Trace.WriteLine (sprintf "view: TryGetMember %s" binder.Name)
if props.ContainsKey binder.Name then
let v = this.[binder.Name]
result <- v
@ -195,7 +196,7 @@ and ViewModel<'model, 'msg>(m: 'model, dispatch: 'msg -> unit, propMap: ViewBind
/// Used by the view to try to set values
override this.TrySetMember (binder, value) =
if debug then console.log (sprintf "view: TrySetMember %s" binder.Name)
if debug then Trace.WriteLine (sprintf "view: TrySetMember %s" binder.Name)
if props.ContainsKey binder.Name then
this.[binder.Name] <- value
false

Просмотреть файл

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Mono.Cecil" Version="0.10.0" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
</ItemGroup>
</Project>

578
Generator/Program.cs Normal file
Просмотреть файл

@ -0,0 +1,578 @@
// dotnet build Generator\Generator.csproj && dotnet Generator\bin\Debug\netcoreapp2.0\Generator.dll Generator\bindings.json Elmish.XamarinForms\DynamicXaml.fs && fsc -a -r:packages\androidapp\Xamarin.Forms\lib\netstandard1.0\Xamarin.Forms.Core.dll Elmish.XamarinForms\DynamicXamlConverters.fs Elmish.XamarinForms\DynamicXaml.fs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Mono.Cecil;
using Newtonsoft.Json;
namespace Generator
{
class Bindings
{
// Input
public List<string> Assemblies { get; set; }
public List<TypeBinding> Types { get; set; }
public string OutputNamespace { get; set; }
// Output
public List<AssemblyDefinition> AssemblyDefinitions { get; set; }
public TypeDefinition GetTypeDefinition(string name) =>
(from a in AssemblyDefinitions
from m in a.Modules
from tdef in m.Types
where tdef.FullName == name
select tdef).First();
public TypeBinding FindType (string name) => Types.FirstOrDefault (x => x.Name == name);
}
class TypeBinding
{
// Input
public string Name { get; set; }
public List<MemberBinding> Members { get; set; }
// Output
public string BoundCode { get; set; }
public TypeDefinition Definition { get; set; }
public string BoundName => "XamlElement"; // Definition.Name + "Description";
}
class MemberBinding
{
// Input
public string Name { get; set; }
public string UniqueName { get; set; }
public string ShortName { get; set; }
public string Default { get; set; }
public string Equality { get; set; }
public string Conv { get; set; }
public string ModelType { get; set; }
public string ElementType { get; set; }
public string InputType { get; set; }
public List<MemberBinding> Attached { get; set; }
// Output
public MemberReference Definition { get; set; }
public TypeReference BoundType =>
(Definition is PropertyDefinition p)
? p.PropertyType
: ((EventDefinition)Definition).EventType;
public string BoundUniqueName => string.IsNullOrEmpty(UniqueName) ? Name : UniqueName;
public string LowerBoundUniqueName => char.ToLowerInvariant (BoundUniqueName[0]) + BoundUniqueName.Substring (1);
public string BoundShortName => string.IsNullOrEmpty(ShortName) ? Name : ShortName;
public string LowerBoundShortName => char.ToLowerInvariant(BoundShortName[0]) + BoundShortName.Substring(1);
public string GetInputType(Bindings bindings, IEnumerable<Tuple<TypeReference, TypeDefinition>> hierarchy)
{
if (!string.IsNullOrWhiteSpace(InputType))
{
return InputType;
}
return this.GetModelType(bindings, hierarchy);
}
public string GetModelType(Bindings bindings, IEnumerable<Tuple<TypeReference, TypeDefinition>> hierarchy)
{
if (!string.IsNullOrWhiteSpace(ModelType))
{
return ModelType;
}
return GetModelTypeInner(bindings, this.BoundType, hierarchy);
}
public static string GetModelTypeInner(Bindings bindings, TypeReference tref, IEnumerable<Tuple<TypeReference, TypeDefinition>> hierarchy)
{
if (tref.IsGenericParameter)
{
if (hierarchy != null)
{
var r = Program.ResolveGenericParameter(tref, hierarchy);
return GetModelTypeInner(bindings, r, hierarchy);
}
else
{
return "XamlElement";
}
}
if (tref.IsGenericInstance)
{
var n = tref.Name.Substring(0, tref.Name.IndexOf('`'));
var ns = tref.Namespace;
if (tref.IsNested)
{
n = tref.DeclaringType.Name + "." + n;
ns = tref.DeclaringType.Namespace;
}
var args = string.Join(", ", ((GenericInstanceType)tref).GenericArguments.Select(s => GetModelTypeInner(bindings, s, hierarchy)));
return $"{ns}.{n}<{args}>";
}
switch (tref.FullName)
{
case "System.String": return "string";
case "System.Boolean": return "bool";
case "System.Int32": return "int";
case "System.Double": return "double";
case "System.Single": return "single";
default:
if (bindings.Types.FirstOrDefault(x => x.Name == tref.FullName) is TypeBinding tb)
return tb.BoundName;
return tref.FullName.Replace('/', '.');
}
}
public string GetElementType(IEnumerable<Tuple<TypeReference, TypeDefinition>> hierarchy)
{
if (!string.IsNullOrWhiteSpace(ElementType))
{
return ElementType;
}
return GetElementTypeInner(this.BoundType, hierarchy);
}
static string GetElementTypeInner(TypeReference tref, IEnumerable<Tuple<TypeReference, TypeDefinition>> hierarchy)
{
var r = Program.ResolveGenericParameter(tref, hierarchy);
if (r == null)
return null;
if (r.FullName == "System.String")
return null;
if (r.Name == "IList`1" && r.IsGenericInstance)
{
var args = ((GenericInstanceType)r).GenericArguments;
var elementType = Program.ResolveGenericParameter(args[0], hierarchy);
return elementType.Name;
}
else
{
var bs = r.Resolve().Interfaces;
return bs.Select(b => GetElementTypeInner(b.InterfaceType, hierarchy)).FirstOrDefault(b => b != null);
}
}
}
class Program
{
static int Main(string[] args)
{
try {
if (args.Length < 2)
{
Console.Error.WriteLine("usage: generator <outputPath>");
Environment.Exit(1);
}
var bindingsPath = args[0];
var outputPath = args[1];
var bindings = JsonConvert.DeserializeObject<Bindings> (File.ReadAllText (bindingsPath));
bindings.AssemblyDefinitions = bindings.Assemblies.Select(LoadAssembly).ToList();
foreach (var x in bindings.Types)
x.Definition = bindings.GetTypeDefinition (x.Name);
foreach (var x in bindings.Types) {
foreach (var m in x.Members) {
if (FindProperty (m.Name, x.Definition) is PropertyDefinition p) {
m.Definition = p;
}
else if (FindEvent (m.Name, x.Definition) is EventDefinition e) {
m.Definition = e;
}
else {
throw new Exception ($"Could not find member `{m.Name}`");
}
}
}
var code = BindTypes (bindings);
File.WriteAllText (outputPath, code);
return 0;
}
catch (Exception ex) {
System.Console.WriteLine(ex);
return 1;
}
}
static string BindTypes (Bindings bindings)
{
var w = new StringWriter();
var head = "";
w.WriteLine("namespace rec " + bindings.OutputNamespace);
w.WriteLine();
w.WriteLine("#nowarn \"67\" // cast always holds");
w.WriteLine();
w.WriteLine("open System");
w.WriteLine("open System.Diagnostics");
w.WriteLine();
w.WriteLine($"/// A description of a visual element");
w.WriteLine($"[<AllowNullLiteral>]");
w.WriteLine($"type XamlElement(targetType: Type, create: (unit -> obj), apply: (XamlElement option -> XamlElement -> obj -> unit), attribs: Map<string, obj>) = ");
w.WriteLine();
w.WriteLine($" /// Get the type created by the visual element");
w.WriteLine($" member x.TargetType = targetType");
w.WriteLine();
w.WriteLine($" /// Get the attributes of the visual element");
w.WriteLine($" [<DebuggerBrowsable(DebuggerBrowsableState.RootHidden)>]");
w.WriteLine($" member x.Attributes = attribs");
w.WriteLine();
w.WriteLine($" /// Apply the description to a visual element");
w.WriteLine($" member x.Apply (target: obj) = apply None x target");
w.WriteLine();
w.WriteLine($" /// Apply a different description to a similar visual element");
w.WriteLine($" [<DebuggerBrowsable(DebuggerBrowsableState.Never)>]");
w.WriteLine($" member x.ApplyMethod = apply");
w.WriteLine();
w.WriteLine($" /// Incrementally apply a description to a visual element");
w.WriteLine($" member x.ApplyIncremental(prev: XamlElement, target: obj) = apply (Some prev) x target");
w.WriteLine();
w.WriteLine($" /// Apply a different description to a similar visual element");
w.WriteLine($" [<DebuggerBrowsable(DebuggerBrowsableState.Never)>]");
w.WriteLine($" member x.CreateMethod = create");
w.WriteLine();
w.WriteLine($" /// Produce a new visual element with an adjusted attribute");
w.WriteLine($" member x.WithAttribute(name: string, value: obj) = XamlElement(targetType, create, apply, x.Attributes.Add(name, value))");
w.WriteLine();
w.WriteLine($" /// Produce a visual element from a visual element for a different type");
w.WriteLine($" member x.Inherit(newTargetType, newCreate, newApply, newAttribs) = ");
w.WriteLine($" let combinedAttribs = Map.ofArray(Array.append(Map.toArray attribs) newAttribs)");
w.WriteLine($" XamlElement(newTargetType, newCreate, (fun prevOpt source target -> apply prevOpt source target; newApply prevOpt source target), combinedAttribs)");
w.WriteLine();
w.WriteLine($" /// Produce a new visual element with an adjusted attribute");
w.WriteLine($"[<AutoOpen>]");
w.WriteLine($"module XamlElementExtensions = ");
w.WriteLine();
w.WriteLine($" type XamlElement with");
w.WriteLine($" /// Create the UI element from the view description");
w.WriteLine($" member x.Create() : obj =");
w.WriteLine($" let target = x.CreateMethod()");
w.WriteLine($" x.Apply(target)");
w.WriteLine($" target");
foreach (var type in bindings.Types)
{
var tdef = type.Definition;
var hierarchy = GetHierarchy(type.Definition).ToList();
var ctor = tdef.Methods
.Where(x => x.IsConstructor && x.IsPublic)
.OrderBy(x => x.Parameters.Count)
.FirstOrDefault();
w.WriteLine();
w.WriteLine($" /// Create a {tdef.FullName} from the view description");
w.WriteLine($" member x.CreateAs{tdef.Name}() : {tdef.FullName} = (x.Create() :?> {tdef.FullName})");
}
var allMembersInAllTypes = new List<MemberBinding>();
foreach (var type in bindings.Types)
{
if (type.Members != null)
{
foreach (var y in type.Members)
{
allMembersInAllTypes.Add(y);
if (y.Attached != null)
{
foreach (var ap in y.Attached)
allMembersInAllTypes.Add(ap);
}
}
}
}
var allMembersInAllTypesGroupedByName = allMembersInAllTypes.GroupBy(y => y.BoundUniqueName);
/* foreach (var ms in allMembersInAllTypesGroupedByName)
{
var m = ms.First();
w.WriteLine();
w.WriteLine($" /// Get the {m.BoundUniqueName} property in the visual element");
w.WriteLine(" member x." + m.BoundUniqueName + " = match x.Attributes.TryFind(\"" + m.BoundUniqueName + "\") with Some v -> unbox<" + GetModelType(bindings, m.BoundType, null) + ">(v) | None -> " + m.Default);
}
*/
foreach (var ms in allMembersInAllTypesGroupedByName)
{
var m = ms.First();
w.WriteLine();
w.WriteLine($" /// Try to get the {m.BoundUniqueName} property in the visual element");
var modelType = m.GetModelType(bindings, null);
w.WriteLine(" member x.Try" + m.BoundUniqueName + " = match x.Attributes.TryFind(\"" + m.BoundUniqueName + "\") with Some v -> Some(unbox<" + modelType + ">(v)) | None -> None");
}
foreach (var ms in allMembersInAllTypesGroupedByName)
{
var m = ms.First();
w.WriteLine();
w.WriteLine($" /// Adjusts the {m.BoundUniqueName} property in the visual element");
var conv = string.IsNullOrWhiteSpace(m.Conv) ? "" : m.Conv;
var inputType = m.GetInputType(bindings, null);
w.WriteLine(" member x." + m.BoundUniqueName + "(value: " + inputType + ") = XamlElement(x.TargetType, x.CreateMethod, x.ApplyMethod, x.Attributes.Add(\"" + m.BoundUniqueName + "\", box (" + conv + "(value))))");
}
w.WriteLine();
foreach (var ms in allMembersInAllTypesGroupedByName)
{
var m = ms.First();
var inputType = m.GetInputType(bindings, null);
w.WriteLine();
w.WriteLine($" /// Adjusts the {m.BoundUniqueName} property in the visual element");
w.WriteLine(" let with" + m.BoundUniqueName + " (value: " + inputType + ") (x: XamlElement) = x." + m.BoundUniqueName + "(value)");
w.WriteLine();
w.WriteLine($" /// Adjusts the {m.BoundUniqueName} property in the visual element");
w.WriteLine(" let " + m.LowerBoundUniqueName + " (value: " + inputType + ") (x: XamlElement) = x." + m.BoundUniqueName + "(value)");
}
w.WriteLine();
w.WriteLine("type Xaml() =");
foreach (var type in bindings.Types)
{
var tdef = type.Definition;
var hierarchy = GetHierarchy(type.Definition).ToList();
var boundHierarchy =
hierarchy.Select(x => bindings.Types.FirstOrDefault(y => y.Name == x.Item2.FullName))
.Where(x => x != null)
.ToList();
var baseType = boundHierarchy.Count > 1 ? boundHierarchy[1] : null;
// All properties and events apart from the attached ones
var allDirectMembers = (from x in boundHierarchy from y in x.Members select y).ToList();
// Emit the constructor
w.WriteLine();
w.WriteLine($" /// Describes a {tdef.Name} in the view");
w.Write($" static member {tdef.Name}(");
head = "";
foreach (var m in allDirectMembers)
{
var inputType = m.GetInputType(bindings, null);
w.Write($"{head}?{m.LowerBoundShortName}: {inputType}");
head = ", ";
}
w.WriteLine($") = ");
w.WriteLine($" let attribs = [| ");
foreach (var m in allDirectMembers)
{
var conv = string.IsNullOrWhiteSpace(m.Conv) ? "" : m.Conv;
w.WriteLine(" match " + m.LowerBoundShortName + " with None -> () | Some v -> yield (\"" + m.BoundUniqueName + "\"" + $", box (" + conv + "(v))) ");
}
w.WriteLine($" |]");
var ctor = tdef.Methods
.Where(x => x.IsConstructor && x.IsPublic)
.OrderBy(x => x.Parameters.Count)
.FirstOrDefault();
w.WriteLine();
w.WriteLine($" let create () =");
if (!tdef.IsAbstract && ctor != null && ctor.Parameters.Count == 0)
{
w.WriteLine($" box (new {tdef.FullName}())");
}
else
{
w.WriteLine($" failwith \"can'tdef create {tdef.FullName}\"");
}
w.WriteLine();
w.WriteLine($" let apply (prevOpt: XamlElement option) (source: XamlElement) (target:obj) = ");
if (baseType == null && type.Members.Count() == 0)
{
w.WriteLine($" ()");
}
else
{
w.WriteLine($" let target = (target :?> {tdef.FullName})");
foreach (var m in allDirectMembers)
{
var bt = ResolveGenericParameter(m.BoundType, hierarchy);
string elementType = m.GetElementType(hierarchy);
if (elementType != null && elementType != "obj")
{
w.WriteLine($" match source.Try{m.BoundUniqueName} with");
w.WriteLine($" | Some coll when coll <> null && coll.Length > 0 ->");
w.WriteLine($" if (coll = null || coll.Length = 0) then");
w.WriteLine($" match target.{m.Name} with");
w.WriteLine($" | null -> ()");
w.WriteLine($" | targetColl -> targetColl.Clear() ");
w.WriteLine($" else");
w.WriteLine($" // Remove the excess children");
w.WriteLine($" while (target.{m.Name}.Count > coll.Length) do");
w.WriteLine($" target.{m.Name}.RemoveAt(target.{m.Name}.Count - 1)");
w.WriteLine();
w.WriteLine($" // Count the existing children");
w.WriteLine($" let n = target.{m.Name}.Count;");
w.WriteLine();
w.WriteLine($" // Adjust the existing children and create the new children");
w.WriteLine($" for i in 0 .. coll.Length-1 do");
w.WriteLine($" let newChild = coll.[i]");
w.WriteLine($" let prevChildOpt = match prevOpt with None -> None | Some prev -> match prev.Try{m.BoundUniqueName} with None -> None | Some coll when i < coll.Length && i < n -> Some coll.[i] | _ -> None");
w.WriteLine($" let prevChildOpt, targetChild = ");
w.WriteLine($" if (match prevChildOpt with None -> true | Some prevChild -> not (obj.ReferenceEquals(prevChild, newChild))) then");
w.WriteLine($" let mustCreate = (i >= n || match prevChildOpt with None -> true | Some prevChild -> newChild.TargetType <> prevChild.TargetType)");
w.WriteLine($" if mustCreate then");
w.WriteLine($" let targetChild = newChild.CreateAs{elementType}()");
w.WriteLine($" if i >= n then");
w.WriteLine($" target.{m.Name}.Insert(i, targetChild)");
w.WriteLine($" else");
w.WriteLine($" target.{m.Name}.[i] <- targetChild");
w.WriteLine($" None, targetChild");
w.WriteLine($" else");
w.WriteLine($" let targetChild = target.{m.Name}.[i]");
w.WriteLine($" newChild.ApplyIncremental(prevChildOpt.Value, targetChild)");
w.WriteLine($" prevChildOpt, targetChild");
w.WriteLine($" else");
w.WriteLine($" prevChildOpt, target.{m.Name}.[i]");
if (m.Attached != null)
{
foreach (var ap in m.Attached)
{
w.WriteLine($" // Adjust the attached properties");
w.WriteLine($" match (match prevChildOpt with None -> None | Some prevChild -> prevChild.Try{ap.BoundUniqueName}), newChild.Try{ap.BoundUniqueName} with");
w.WriteLine($" | Some prev, Some v when prev = v -> ()");
w.WriteLine($" | _, Some v -> {tdef.FullName}.Set{ap.Name}(targetChild, v)");
w.WriteLine($" | Some _, None -> {tdef.FullName}.Set{ap.Name}(targetChild, {ap.Default}) // TODO: not always perfect, should set back to original default?");
w.WriteLine($" | _ -> ()");
}
}
w.WriteLine($" ()");
w.WriteLine($" | _ -> ()");
}
else
{
if (bindings.FindType(bt.FullName) is TypeBinding b)
{
if (bt.IsValueType)
{
w.WriteLine($" let prevChildOpt = match prevOpt with None -> None | Some prev -> prev.Try{m.BoundUniqueName}");
w.WriteLine($" match prevChildOpt, source.Try{m.BoundUniqueName} with");
w.WriteLine($" // For structured objects, the only caching is based on reference equality");
w.WriteLine($" | Some prevChild, Some newChild when obj.ReferenceEquals(prevChild, newChild) -> ()");
w.WriteLine($" | _, Some newChild ->");
w.WriteLine($" target.{m.Name} <- newChild.CreateAs{bt.Name}()");
w.WriteLine($" | _, None ->");
w.WriteLine($" target.{m.Name} <- Unchecked.defaultof<_>");
}
else
{
w.WriteLine($" let prevChildOpt = match prevOpt with None -> None | Some prev -> prev.Try{m.BoundUniqueName}");
w.WriteLine($" match prevChildOpt, source.Try{m.BoundUniqueName} with");
w.WriteLine($" // For structured objects, the only caching is based on reference equality");
w.WriteLine($" | Some prevChild, Some newChild when obj.ReferenceEquals(prevChild, newChild) -> ()");
w.WriteLine($" | Some prevChild, Some newChild ->");
w.WriteLine($" newChild.ApplyIncremental(prevChild, target.{m.Name})");
w.WriteLine($" | None, Some newChild ->");
w.WriteLine($" target.{m.Name} <- newChild.CreateAs{bt.Name}()");
w.WriteLine($" | _, None ->");
w.WriteLine($" target.{m.Name} <- null;");
}
}
else if (bt.Name.EndsWith("Handler") || bt.Name.EndsWith("Handler`1") || bt.Name.EndsWith("Handler`2"))
{
w.WriteLine($" let prevValueOpt = match prevOpt with None -> None | Some prev -> prev.Try{m.BoundUniqueName}");
w.WriteLine($" match prevValueOpt, source.Try{m.BoundUniqueName} with");
w.WriteLine($" | Some prevValue, Some value when prevValue = value -> ()");
w.WriteLine($" | Some prevValue, Some value -> target.{m.Name}.RemoveHandler(prevValue); target.{m.Name}.AddHandler(value)");
w.WriteLine($" | None, Some value -> target.{m.Name}.AddHandler(value)");
w.WriteLine($" | Some prevValue, None -> target.{m.Name}.RemoveHandler(prevValue)");
w.WriteLine($" | None, None -> ()");
}
else
{
w.WriteLine($" let prevValueOpt = match prevOpt with None -> None | Some prev -> prev.Try{m.BoundUniqueName}");
w.WriteLine($" match prevValueOpt, source.Try{m.BoundUniqueName} with");
w.WriteLine($" | Some prevValue, Some value when prevValue = value -> ()");
w.WriteLine($" | _, Some value -> target.{m.Name} <- value");
w.WriteLine($" | Some _, None -> target.{m.Name} <- {m.Default} // TODO: not always perfect, should set back to original default?");
w.WriteLine($" | None, None -> ()");
}
}
}
}
w.WriteLine($" new XamlElement(typeof<{tdef.FullName}>, create, apply, Map.ofArray attribs)");
}
w.WriteLine($"[<AutoOpen>]");
w.WriteLine($"module XamlCreateExtensions = ");
foreach (var type in bindings.Types)
{
var tdef = type.Definition;
var hierarchy = GetHierarchy(type.Definition).ToList();
var boundHierarchy = hierarchy.Select(x => bindings.Types.FirstOrDefault(y => y.Name == x.Item2.FullName))
.Where(x => x != null)
.ToList();
var ctor = tdef.Methods
.Where(x => x.IsConstructor && x.IsPublic)
.OrderBy(x => x.Parameters.Count)
.FirstOrDefault();
if (!tdef.IsAbstract && ctor != null && ctor.Parameters.Count == 0)
{
w.WriteLine();
w.WriteLine($" /// Specifies a {tdef.Name} in the view description, initially with default attributes");
w.WriteLine($" let {Char.ToLower(tdef.Name[0])}{tdef.Name.Substring(1)} = Xaml.{tdef.Name}()");
}
}
return w.ToString ();
}
static public TypeReference ResolveGenericParameter (TypeReference tref, IEnumerable<Tuple<TypeReference, TypeDefinition>> hierarchy)
{
if (tref == null)
return null;
if (!tref.IsGenericParameter)
return tref;
var q =
from b in hierarchy where b.Item1.IsGenericInstance
let ps = b.Item2.GenericParameters
let p = ps.FirstOrDefault(x => x.Name == tref.Name)
where p != null
let pi = ps.IndexOf(p)
let args = ((GenericInstanceType)b.Item1).GenericArguments
select ResolveGenericParameter (args[pi], hierarchy);
return q.First ();
}
static PropertyDefinition FindProperty(string name, TypeDefinition type)
{
var q =
from tdef in GetHierarchy(type)
from p in tdef.Item2.Properties
where p.Name == name
select p;
return q.FirstOrDefault ();
}
static EventDefinition FindEvent(string name, TypeDefinition type)
{
var q =
from tdef in GetHierarchy(type)
from p in tdef.Item2.Events
where p.Name == name
select p;
return q.FirstOrDefault ();
}
static IEnumerable<Tuple<TypeReference, TypeDefinition>> GetHierarchy (TypeDefinition type)
{
var d = type;
yield return Tuple.Create ((TypeReference)d, d);
while (d.BaseType != null) {
var r = d.BaseType;
d = r.Resolve();
yield return Tuple.Create (r, d);
}
}
static AssemblyDefinition LoadAssembly (string path)
{
if (path.StartsWith("packages")) {
var user = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
path = Path.Combine (user, ".nuget", path);
}
return AssemblyDefinition.ReadAssembly(path);
}
}
}

1123
Generator/bindings.json Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -55,6 +55,7 @@ type AllControls () =
( "White", Color.White ); ( "Yellow", Color.Yellow ) ]
let view (model: Model) dispatch =
Xaml.ContentPage(
Xaml.ScrollView(
Xaml.StackLayout(padding=20.0,
children=[
@ -127,7 +128,6 @@ type AllControls () =
// Xaml.BoxView: TODO
// Xaml.Cell, EntryCell: TODO
// Xaml.CarouselPage: TODO
// Xaml.ContentPage: TODO
// Xaml.MasterDetailPage: TODO
// Xaml.Menu: TODO
// Xaml.MenuItem: TODO
@ -149,13 +149,13 @@ type AllControls () =
Xaml.ListView(itemsSource= ["Ionide"; "Visual Studio"; "Emacs"; "Visual Studio Code"; "Rider"], horizontalOptions=LayoutOptions.CenterAndExpand,
itemSelected=(fun item -> dispatch (ListViewSelectedItemChanged item)))
]))
])))
do
let page =
Program.mkSimple init update
(fun _ _ -> HelperPage(), [], view)
Program.mkSimple init update view
|> Program.withConsoleTrace
|> Program.runDynamicView
|> Program.withDynamicView
|> Program.run
base.MainPage <- page

Просмотреть файл

@ -10,15 +10,16 @@
<OutputType>Library</OutputType>
<RootNamespace>Droid</RootNamespace>
<AssemblyName>Droid</AssemblyName>
<TargetFrameworkVersion>v7.1</TargetFrameworkVersion>
<TargetFrameworkVersion>v8.1</TargetFrameworkVersion>
<AndroidApplication>True</AndroidApplication>
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
<AndroidResgenClass>Resource</AndroidResgenClass>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
<AndroidUseLatestPlatformSdk>true</AndroidUseLatestPlatformSdk>
<SelectedDevice>Google Pixel 2</SelectedDevice>
<DefaultDevice>new_device</DefaultDevice>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>

Просмотреть файл

@ -29,8 +29,9 @@ type CounterApp () =
| SetStep n -> { model with Step = n }
let view (model: Model) dispatch =
Xaml.StackLayout(padding=20.0,
children=[
Xaml.ContentPage(
content=Xaml.StackLayout(padding=20.0,
children=[
yield Xaml.StackLayout(padding=20.0, verticalOptions=LayoutOptions.Center,
children=[
Xaml.Label(text= sprintf "%d" model.Count, horizontalOptions=LayoutOptions.Center, textColor=Color.Blue)
@ -42,13 +43,13 @@ type CounterApp () =
])
if model <> init() then
yield Xaml.Button(text="Reset", horizontalOptions=LayoutOptions.Center, command= (fun () -> dispatch Reset))
])
]))
do
let page =
Program.mkSimple init update
(fun _ _ -> HelperPage(), [], view)
Program.mkSimple init update view
|> Program.withConsoleTrace
|> Program.runDynamicView
|> Program.withDynamicView
|> Program.run
base.MainPage <- page

Просмотреть файл

@ -3,6 +3,7 @@ namespace CounterApp
open Elmish
open Elmish.XamarinForms
open Elmish.XamarinForms.StaticViews
open Xamarin.Forms
type Model =
@ -39,8 +40,9 @@ type CounterApp () =
do
let page =
Program.mkSimple init update (fun _ _ -> view())
Program.mkSimple init update view
|> Program.withConsoleTrace
|> Program.withStaticView
|> Program.run
base.MainPage <- page

Просмотреть файл

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\packages\androidapp\Xamarin.Forms\build\netstandard1.0\Xamarin.Forms.props" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Forms\build\netstandard1.0\Xamarin.Forms.props')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Forms\build\netstandard1.0\Xamarin.Forms.props" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Forms\build\netstandard1.0\Xamarin.Forms.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@ -46,22 +46,22 @@
</PlatformTarget>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.FSharp.targets" Condition="Exists('$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.FSharp.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.Compat\build\MonoAndroid70\Xamarin.Android.Support.Compat.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.Compat\build\MonoAndroid70\Xamarin.Android.Support.Compat.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.Core.UI\build\MonoAndroid70\Xamarin.Android.Support.Core.UI.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.Core.UI\build\MonoAndroid70\Xamarin.Android.Support.Core.UI.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.Core.Utils\build\MonoAndroid70\Xamarin.Android.Support.Core.Utils.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.Core.Utils\build\MonoAndroid70\Xamarin.Android.Support.Core.Utils.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.Media.Compat\build\MonoAndroid70\Xamarin.Android.Support.Media.Compat.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.Media.Compat\build\MonoAndroid70\Xamarin.Android.Support.Media.Compat.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.Fragment\build\MonoAndroid70\Xamarin.Android.Support.Fragment.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.Fragment\build\MonoAndroid70\Xamarin.Android.Support.Fragment.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.v4\build\MonoAndroid70\Xamarin.Android.Support.v4.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.v4\build\MonoAndroid70\Xamarin.Android.Support.v4.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.Transition\build\MonoAndroid70\Xamarin.Android.Support.Transition.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.Transition\build\MonoAndroid70\Xamarin.Android.Support.Transition.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.v7.CardView\build\MonoAndroid70\Xamarin.Android.Support.v7.CardView.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.v7.CardView\build\MonoAndroid70\Xamarin.Android.Support.v7.CardView.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.v7.Palette\build\MonoAndroid70\Xamarin.Android.Support.v7.Palette.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.v7.Palette\build\MonoAndroid70\Xamarin.Android.Support.v7.Palette.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.v7.RecyclerView\build\MonoAndroid70\Xamarin.Android.Support.v7.RecyclerView.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.v7.RecyclerView\build\MonoAndroid70\Xamarin.Android.Support.v7.RecyclerView.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.Vector.Drawable\build\MonoAndroid70\Xamarin.Android.Support.Vector.Drawable.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.Vector.Drawable\build\MonoAndroid70\Xamarin.Android.Support.Vector.Drawable.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.Animated.Vector.Drawable\build\MonoAndroid70\Xamarin.Android.Support.Animated.Vector.Drawable.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.Animated.Vector.Drawable\build\MonoAndroid70\Xamarin.Android.Support.Animated.Vector.Drawable.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.v7.AppCompat\build\MonoAndroid70\Xamarin.Android.Support.v7.AppCompat.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.v7.AppCompat\build\MonoAndroid70\Xamarin.Android.Support.v7.AppCompat.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.Design\build\MonoAndroid70\Xamarin.Android.Support.Design.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.Design\build\MonoAndroid70\Xamarin.Android.Support.Design.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.v7.MediaRouter\build\MonoAndroid70\Xamarin.Android.Support.v7.MediaRouter.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.v7.MediaRouter\build\MonoAndroid70\Xamarin.Android.Support.v7.MediaRouter.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Forms\build\netstandard1.0\Xamarin.Forms.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Forms\build\netstandard1.0\Xamarin.Forms.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.Compat\build\MonoAndroid70\Xamarin.Android.Support.Compat.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.Compat\build\MonoAndroid70\Xamarin.Android.Support.Compat.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.Core.UI\build\MonoAndroid70\Xamarin.Android.Support.Core.UI.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.Core.UI\build\MonoAndroid70\Xamarin.Android.Support.Core.UI.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.Core.Utils\build\MonoAndroid70\Xamarin.Android.Support.Core.Utils.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.Core.Utils\build\MonoAndroid70\Xamarin.Android.Support.Core.Utils.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.Media.Compat\build\MonoAndroid70\Xamarin.Android.Support.Media.Compat.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.Media.Compat\build\MonoAndroid70\Xamarin.Android.Support.Media.Compat.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.Fragment\build\MonoAndroid70\Xamarin.Android.Support.Fragment.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.Fragment\build\MonoAndroid70\Xamarin.Android.Support.Fragment.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.v4\build\MonoAndroid70\Xamarin.Android.Support.v4.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.v4\build\MonoAndroid70\Xamarin.Android.Support.v4.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.Transition\build\MonoAndroid70\Xamarin.Android.Support.Transition.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.Transition\build\MonoAndroid70\Xamarin.Android.Support.Transition.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.v7.CardView\build\MonoAndroid70\Xamarin.Android.Support.v7.CardView.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.v7.CardView\build\MonoAndroid70\Xamarin.Android.Support.v7.CardView.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.v7.Palette\build\MonoAndroid70\Xamarin.Android.Support.v7.Palette.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.v7.Palette\build\MonoAndroid70\Xamarin.Android.Support.v7.Palette.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.v7.RecyclerView\build\MonoAndroid70\Xamarin.Android.Support.v7.RecyclerView.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.v7.RecyclerView\build\MonoAndroid70\Xamarin.Android.Support.v7.RecyclerView.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.Vector.Drawable\build\MonoAndroid70\Xamarin.Android.Support.Vector.Drawable.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.Vector.Drawable\build\MonoAndroid70\Xamarin.Android.Support.Vector.Drawable.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.Animated.Vector.Drawable\build\MonoAndroid70\Xamarin.Android.Support.Animated.Vector.Drawable.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.Animated.Vector.Drawable\build\MonoAndroid70\Xamarin.Android.Support.Animated.Vector.Drawable.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.v7.AppCompat\build\MonoAndroid70\Xamarin.Android.Support.v7.AppCompat.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.v7.AppCompat\build\MonoAndroid70\Xamarin.Android.Support.v7.AppCompat.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.Design\build\MonoAndroid70\Xamarin.Android.Support.Design.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.Design\build\MonoAndroid70\Xamarin.Android.Support.Design.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.v7.MediaRouter\build\MonoAndroid70\Xamarin.Android.Support.v7.MediaRouter.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.v7.MediaRouter\build\MonoAndroid70\Xamarin.Android.Support.v7.MediaRouter.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Forms\build\netstandard1.0\Xamarin.Forms.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Forms\build\netstandard1.0\Xamarin.Forms.targets')" />
<ItemGroup>
<Compile Include="MainActivity.fs" />
<None Include="Resources\AboutResources.txt" />
@ -90,76 +90,76 @@
<Name>Elmish.XamarinForms</Name>
</ProjectReference>
<Reference Include="Xamarin.Android.FSharp.ResourceProvider.Runtime">
<HintPath>../../../packages/androidapp/Xamarin.Android.FSharp.ResourceProvider/lib/Xamarin.Android.FSharp.ResourceProvider.Runtime.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.FSharp.ResourceProvider/lib/Xamarin.Android.FSharp.ResourceProvider.Runtime.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Animated.Vector.Drawable">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.Animated.Vector.Drawable/lib/MonoAndroid70/Xamarin.Android.Support.Animated.Vector.Drawable.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.Animated.Vector.Drawable/lib/MonoAndroid70/Xamarin.Android.Support.Animated.Vector.Drawable.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Annotations">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.Annotations/lib/MonoAndroid70/Xamarin.Android.Support.Annotations.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.Annotations/lib/MonoAndroid70/Xamarin.Android.Support.Annotations.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Compat">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.Compat/lib/MonoAndroid70/Xamarin.Android.Support.Compat.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.Compat/lib/MonoAndroid70/Xamarin.Android.Support.Compat.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Core.UI">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.Core.UI/lib/MonoAndroid70/Xamarin.Android.Support.Core.UI.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.Core.UI/lib/MonoAndroid70/Xamarin.Android.Support.Core.UI.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Core.Utils">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.Core.Utils/lib/MonoAndroid70/Xamarin.Android.Support.Core.Utils.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.Core.Utils/lib/MonoAndroid70/Xamarin.Android.Support.Core.Utils.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Design">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.Design/lib/MonoAndroid70/Xamarin.Android.Support.Design.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.Design/lib/MonoAndroid70/Xamarin.Android.Support.Design.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Fragment">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.Fragment/lib/MonoAndroid70/Xamarin.Android.Support.Fragment.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.Fragment/lib/MonoAndroid70/Xamarin.Android.Support.Fragment.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Media.Compat">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.Media.Compat/lib/MonoAndroid70/Xamarin.Android.Support.Media.Compat.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.Media.Compat/lib/MonoAndroid70/Xamarin.Android.Support.Media.Compat.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Transition">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.Transition/lib/MonoAndroid70/Xamarin.Android.Support.Transition.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.Transition/lib/MonoAndroid70/Xamarin.Android.Support.Transition.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.v4">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.v4/lib/MonoAndroid70/Xamarin.Android.Support.v4.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.v4/lib/MonoAndroid70/Xamarin.Android.Support.v4.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.v7.AppCompat">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.v7.AppCompat/lib/MonoAndroid70/Xamarin.Android.Support.v7.AppCompat.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.v7.AppCompat/lib/MonoAndroid70/Xamarin.Android.Support.v7.AppCompat.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.v7.CardView">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.v7.CardView/lib/MonoAndroid70/Xamarin.Android.Support.v7.CardView.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.v7.CardView/lib/MonoAndroid70/Xamarin.Android.Support.v7.CardView.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.v7.MediaRouter">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.v7.MediaRouter/lib/MonoAndroid70/Xamarin.Android.Support.v7.MediaRouter.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.v7.MediaRouter/lib/MonoAndroid70/Xamarin.Android.Support.v7.MediaRouter.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.v7.Palette">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.v7.Palette/lib/MonoAndroid70/Xamarin.Android.Support.v7.Palette.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.v7.Palette/lib/MonoAndroid70/Xamarin.Android.Support.v7.Palette.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.v7.RecyclerView">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.v7.RecyclerView/lib/MonoAndroid70/Xamarin.Android.Support.v7.RecyclerView.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.v7.RecyclerView/lib/MonoAndroid70/Xamarin.Android.Support.v7.RecyclerView.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Vector.Drawable">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.Vector.Drawable/lib/MonoAndroid70/Xamarin.Android.Support.Vector.Drawable.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.Vector.Drawable/lib/MonoAndroid70/Xamarin.Android.Support.Vector.Drawable.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Core">
<HintPath>../../../packages/androidapp/Xamarin.Forms/lib/MonoAndroid10/Xamarin.Forms.Core.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Forms/lib/MonoAndroid10/Xamarin.Forms.Core.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Platform">
<HintPath>../../../packages/androidapp/Xamarin.Forms/lib/MonoAndroid10/Xamarin.Forms.Platform.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Forms/lib/MonoAndroid10/Xamarin.Forms.Platform.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Platform.Android">
<HintPath>../../../packages/androidapp/Xamarin.Forms/lib/MonoAndroid10/Xamarin.Forms.Platform.Android.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Forms/lib/MonoAndroid10/Xamarin.Forms.Platform.Android.dll</HintPath>
</Reference>
<Reference Include="FormsViewGroup">
<HintPath>../../../packages/androidapp/Xamarin.Forms/lib/MonoAndroid10/FormsViewGroup.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Forms/lib/MonoAndroid10/FormsViewGroup.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Xaml">
<HintPath>../../../packages/androidapp/Xamarin.Forms/lib/MonoAndroid10/Xamarin.Forms.Xaml.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Forms/lib/MonoAndroid10/Xamarin.Forms.Xaml.dll</HintPath>
</Reference>
<Reference Include="FSharp.Core">
<HintPath>..\..\..\packages\FSharp.Core.4.3.4\lib\netstandard1.6\FSharp.Core.dll</HintPath>
<HintPath>../../../../packages/FSharp.Core.4.3.4/lib/netstandard1.6/FSharp.Core.dll</HintPath>
</Reference>
<Reference Include="FSharp.Control.AsyncSeq">
<HintPath>..\..\..\packages\FSharp.Control.AsyncSeq.2.0.21\lib\netstandard2.0\FSharp.Control.AsyncSeq.dll</HintPath>
<HintPath>../../../../packages/FSharp.Control.AsyncSeq.2.0.21/lib/netstandard2.0/FSharp.Control.AsyncSeq.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

Просмотреть файл

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\packages\androidapp\Xamarin.Forms\build\netstandard1.0\Xamarin.Forms.props" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Forms\build\netstandard1.0\Xamarin.Forms.props')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Forms\build\netstandard1.0\Xamarin.Forms.props" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Forms\build\netstandard1.0\Xamarin.Forms.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@ -48,22 +48,22 @@
</PlatformTarget>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.FSharp.targets" Condition="Exists('$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.FSharp.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.Compat\build\MonoAndroid70\Xamarin.Android.Support.Compat.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.Compat\build\MonoAndroid70\Xamarin.Android.Support.Compat.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.Core.UI\build\MonoAndroid70\Xamarin.Android.Support.Core.UI.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.Core.UI\build\MonoAndroid70\Xamarin.Android.Support.Core.UI.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.Core.Utils\build\MonoAndroid70\Xamarin.Android.Support.Core.Utils.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.Core.Utils\build\MonoAndroid70\Xamarin.Android.Support.Core.Utils.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.Media.Compat\build\MonoAndroid70\Xamarin.Android.Support.Media.Compat.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.Media.Compat\build\MonoAndroid70\Xamarin.Android.Support.Media.Compat.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.Fragment\build\MonoAndroid70\Xamarin.Android.Support.Fragment.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.Fragment\build\MonoAndroid70\Xamarin.Android.Support.Fragment.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.v4\build\MonoAndroid70\Xamarin.Android.Support.v4.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.v4\build\MonoAndroid70\Xamarin.Android.Support.v4.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.Transition\build\MonoAndroid70\Xamarin.Android.Support.Transition.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.Transition\build\MonoAndroid70\Xamarin.Android.Support.Transition.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.v7.CardView\build\MonoAndroid70\Xamarin.Android.Support.v7.CardView.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.v7.CardView\build\MonoAndroid70\Xamarin.Android.Support.v7.CardView.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.v7.Palette\build\MonoAndroid70\Xamarin.Android.Support.v7.Palette.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.v7.Palette\build\MonoAndroid70\Xamarin.Android.Support.v7.Palette.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.v7.RecyclerView\build\MonoAndroid70\Xamarin.Android.Support.v7.RecyclerView.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.v7.RecyclerView\build\MonoAndroid70\Xamarin.Android.Support.v7.RecyclerView.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.Vector.Drawable\build\MonoAndroid70\Xamarin.Android.Support.Vector.Drawable.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.Vector.Drawable\build\MonoAndroid70\Xamarin.Android.Support.Vector.Drawable.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.Animated.Vector.Drawable\build\MonoAndroid70\Xamarin.Android.Support.Animated.Vector.Drawable.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.Animated.Vector.Drawable\build\MonoAndroid70\Xamarin.Android.Support.Animated.Vector.Drawable.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.v7.AppCompat\build\MonoAndroid70\Xamarin.Android.Support.v7.AppCompat.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.v7.AppCompat\build\MonoAndroid70\Xamarin.Android.Support.v7.AppCompat.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.Design\build\MonoAndroid70\Xamarin.Android.Support.Design.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.Design\build\MonoAndroid70\Xamarin.Android.Support.Design.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Android.Support.v7.MediaRouter\build\MonoAndroid70\Xamarin.Android.Support.v7.MediaRouter.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Android.Support.v7.MediaRouter\build\MonoAndroid70\Xamarin.Android.Support.v7.MediaRouter.targets')" />
<Import Project="..\..\..\packages\androidapp\Xamarin.Forms\build\netstandard1.0\Xamarin.Forms.targets" Condition="Exists('..\..\..\packages\androidapp\Xamarin.Forms\build\netstandard1.0\Xamarin.Forms.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.Compat\build\MonoAndroid70\Xamarin.Android.Support.Compat.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.Compat\build\MonoAndroid70\Xamarin.Android.Support.Compat.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.Core.UI\build\MonoAndroid70\Xamarin.Android.Support.Core.UI.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.Core.UI\build\MonoAndroid70\Xamarin.Android.Support.Core.UI.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.Core.Utils\build\MonoAndroid70\Xamarin.Android.Support.Core.Utils.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.Core.Utils\build\MonoAndroid70\Xamarin.Android.Support.Core.Utils.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.Media.Compat\build\MonoAndroid70\Xamarin.Android.Support.Media.Compat.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.Media.Compat\build\MonoAndroid70\Xamarin.Android.Support.Media.Compat.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.Fragment\build\MonoAndroid70\Xamarin.Android.Support.Fragment.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.Fragment\build\MonoAndroid70\Xamarin.Android.Support.Fragment.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.v4\build\MonoAndroid70\Xamarin.Android.Support.v4.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.v4\build\MonoAndroid70\Xamarin.Android.Support.v4.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.Transition\build\MonoAndroid70\Xamarin.Android.Support.Transition.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.Transition\build\MonoAndroid70\Xamarin.Android.Support.Transition.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.v7.CardView\build\MonoAndroid70\Xamarin.Android.Support.v7.CardView.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.v7.CardView\build\MonoAndroid70\Xamarin.Android.Support.v7.CardView.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.v7.Palette\build\MonoAndroid70\Xamarin.Android.Support.v7.Palette.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.v7.Palette\build\MonoAndroid70\Xamarin.Android.Support.v7.Palette.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.v7.RecyclerView\build\MonoAndroid70\Xamarin.Android.Support.v7.RecyclerView.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.v7.RecyclerView\build\MonoAndroid70\Xamarin.Android.Support.v7.RecyclerView.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.Vector.Drawable\build\MonoAndroid70\Xamarin.Android.Support.Vector.Drawable.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.Vector.Drawable\build\MonoAndroid70\Xamarin.Android.Support.Vector.Drawable.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.Animated.Vector.Drawable\build\MonoAndroid70\Xamarin.Android.Support.Animated.Vector.Drawable.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.Animated.Vector.Drawable\build\MonoAndroid70\Xamarin.Android.Support.Animated.Vector.Drawable.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.v7.AppCompat\build\MonoAndroid70\Xamarin.Android.Support.v7.AppCompat.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.v7.AppCompat\build\MonoAndroid70\Xamarin.Android.Support.v7.AppCompat.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.Design\build\MonoAndroid70\Xamarin.Android.Support.Design.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.Design\build\MonoAndroid70\Xamarin.Android.Support.Design.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Android.Support.v7.MediaRouter\build\MonoAndroid70\Xamarin.Android.Support.v7.MediaRouter.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Android.Support.v7.MediaRouter\build\MonoAndroid70\Xamarin.Android.Support.v7.MediaRouter.targets')" />
<Import Project="..\..\..\..\packages\androidapp\Xamarin.Forms\build\netstandard1.0\Xamarin.Forms.targets" Condition="Exists('..\..\..\..\packages\androidapp\Xamarin.Forms\build\netstandard1.0\Xamarin.Forms.targets')" />
<ItemGroup>
<Compile Include="MainActivity.fs" />
<None Include="Resources\AboutResources.txt" />
@ -92,76 +92,76 @@
<Name>Elmish.XamarinForms</Name>
</ProjectReference>
<Reference Include="Xamarin.Android.FSharp.ResourceProvider.Runtime">
<HintPath>../../../packages/androidapp/Xamarin.Android.FSharp.ResourceProvider/lib/Xamarin.Android.FSharp.ResourceProvider.Runtime.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.FSharp.ResourceProvider/lib/Xamarin.Android.FSharp.ResourceProvider.Runtime.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Animated.Vector.Drawable">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.Animated.Vector.Drawable/lib/MonoAndroid70/Xamarin.Android.Support.Animated.Vector.Drawable.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.Animated.Vector.Drawable/lib/MonoAndroid70/Xamarin.Android.Support.Animated.Vector.Drawable.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Annotations">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.Annotations/lib/MonoAndroid70/Xamarin.Android.Support.Annotations.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.Annotations/lib/MonoAndroid70/Xamarin.Android.Support.Annotations.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Compat">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.Compat/lib/MonoAndroid70/Xamarin.Android.Support.Compat.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.Compat/lib/MonoAndroid70/Xamarin.Android.Support.Compat.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Core.UI">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.Core.UI/lib/MonoAndroid70/Xamarin.Android.Support.Core.UI.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.Core.UI/lib/MonoAndroid70/Xamarin.Android.Support.Core.UI.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Core.Utils">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.Core.Utils/lib/MonoAndroid70/Xamarin.Android.Support.Core.Utils.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.Core.Utils/lib/MonoAndroid70/Xamarin.Android.Support.Core.Utils.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Design">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.Design/lib/MonoAndroid70/Xamarin.Android.Support.Design.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.Design/lib/MonoAndroid70/Xamarin.Android.Support.Design.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Fragment">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.Fragment/lib/MonoAndroid70/Xamarin.Android.Support.Fragment.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.Fragment/lib/MonoAndroid70/Xamarin.Android.Support.Fragment.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Media.Compat">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.Media.Compat/lib/MonoAndroid70/Xamarin.Android.Support.Media.Compat.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.Media.Compat/lib/MonoAndroid70/Xamarin.Android.Support.Media.Compat.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Transition">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.Transition/lib/MonoAndroid70/Xamarin.Android.Support.Transition.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.Transition/lib/MonoAndroid70/Xamarin.Android.Support.Transition.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.v4">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.v4/lib/MonoAndroid70/Xamarin.Android.Support.v4.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.v4/lib/MonoAndroid70/Xamarin.Android.Support.v4.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.v7.AppCompat">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.v7.AppCompat/lib/MonoAndroid70/Xamarin.Android.Support.v7.AppCompat.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.v7.AppCompat/lib/MonoAndroid70/Xamarin.Android.Support.v7.AppCompat.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.v7.CardView">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.v7.CardView/lib/MonoAndroid70/Xamarin.Android.Support.v7.CardView.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.v7.CardView/lib/MonoAndroid70/Xamarin.Android.Support.v7.CardView.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.v7.MediaRouter">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.v7.MediaRouter/lib/MonoAndroid70/Xamarin.Android.Support.v7.MediaRouter.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.v7.MediaRouter/lib/MonoAndroid70/Xamarin.Android.Support.v7.MediaRouter.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.v7.Palette">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.v7.Palette/lib/MonoAndroid70/Xamarin.Android.Support.v7.Palette.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.v7.Palette/lib/MonoAndroid70/Xamarin.Android.Support.v7.Palette.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.v7.RecyclerView">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.v7.RecyclerView/lib/MonoAndroid70/Xamarin.Android.Support.v7.RecyclerView.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.v7.RecyclerView/lib/MonoAndroid70/Xamarin.Android.Support.v7.RecyclerView.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.Vector.Drawable">
<HintPath>../../../packages/androidapp/Xamarin.Android.Support.Vector.Drawable/lib/MonoAndroid70/Xamarin.Android.Support.Vector.Drawable.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Android.Support.Vector.Drawable/lib/MonoAndroid70/Xamarin.Android.Support.Vector.Drawable.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Core">
<HintPath>../../../packages/androidapp/Xamarin.Forms/lib/MonoAndroid10/Xamarin.Forms.Core.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Forms/lib/MonoAndroid10/Xamarin.Forms.Core.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Platform">
<HintPath>../../../packages/androidapp/Xamarin.Forms/lib/MonoAndroid10/Xamarin.Forms.Platform.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Forms/lib/MonoAndroid10/Xamarin.Forms.Platform.dll</HintPath>
</Reference>
<Reference Include="FormsViewGroup">
<HintPath>../../../packages/androidapp/Xamarin.Forms/lib/MonoAndroid10/FormsViewGroup.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Forms/lib/MonoAndroid10/FormsViewGroup.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Platform.Android">
<HintPath>../../../packages/androidapp/Xamarin.Forms/lib/MonoAndroid10/Xamarin.Forms.Platform.Android.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Forms/lib/MonoAndroid10/Xamarin.Forms.Platform.Android.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Xaml">
<HintPath>../../../packages/androidapp/Xamarin.Forms/lib/MonoAndroid10/Xamarin.Forms.Xaml.dll</HintPath>
<HintPath>../../../../packages/androidapp/Xamarin.Forms/lib/MonoAndroid10/Xamarin.Forms.Xaml.dll</HintPath>
</Reference>
<Reference Include="FSharp.Control.AsyncSeq">
<HintPath>../../../packages/FSharp.Control.AsyncSeq.2.0.21/lib/netstandard2.0/FSharp.Control.AsyncSeq.dll</HintPath>
<HintPath>../../../../packages/FSharp.Control.AsyncSeq.2.0.21/lib/netstandard2.0/FSharp.Control.AsyncSeq.dll</HintPath>
</Reference>
<Reference Include="FSharp.Core">
<HintPath>../../../packages/androidapp/FSharp.Core.4.3.4/lib/netstandard1.6/FSharp.Core.dll</HintPath>
<HintPath>../../../../packages/androidapp/FSharp.Core.4.3.4/lib/netstandard1.6/FSharp.Core.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

Просмотреть файл

@ -4,6 +4,7 @@ namespace MasterDetailApp
open System
open Elmish
open Elmish.XamarinForms
open Elmish.XamarinForms.StaticViews
open FSharp.Control
open Xamarin.Forms
open Xamarin.Forms.Xaml
@ -51,13 +52,11 @@ type MasterDetailApp () as self =
do
let mainPage =
Program.mkProgram
(fun () -> MainPage.init(), NoCmd)
MainPage.update
(fun _ _ -> MainPage.view())
Program.mkProgram (fun () -> MainPage.init(), NoCmd) MainPage.update MainPage.view
|> Program.withConsoleTrace
|> Program.withNavigation
|> Program.runStaticView
|> Program.withStaticView
|> Program.run
base.MainPage <- NavigationPage mainPage

Просмотреть файл

@ -3,6 +3,7 @@
open Xamarin.Forms
open Xamarin.Forms.Xaml
open Elmish.XamarinForms
open Elmish.XamarinForms.StaticViews
type AboutPage() =
inherit ContentPage()

Просмотреть файл

@ -3,6 +3,7 @@
open Xamarin.Forms
open Xamarin.Forms.Xaml
open Elmish.XamarinForms
open Elmish.XamarinForms.StaticViews
type ItemDetailPage() =
inherit ContentPage()

Просмотреть файл

@ -4,6 +4,7 @@ open FSharp.Control
open Xamarin.Forms
open Xamarin.Forms.Xaml
open Elmish.XamarinForms
open Elmish.XamarinForms.StaticViews
type ItemsPage() =
inherit ContentPage()

Просмотреть файл

@ -4,6 +4,7 @@ namespace MasterDetailApp
open Xamarin.Forms
open Xamarin.Forms.Xaml
open Elmish.XamarinForms
open Elmish.XamarinForms.StaticViews
type NewItemPage() =
inherit ContentPage()

Просмотреть файл

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="io.jimbobbennett.TicTacToe">
<uses-sdk android:minSdkVersion="15" />
<application android:label="TicTacToe">
</application>
</manifest>

Просмотреть файл

@ -0,0 +1,25 @@
namespace TicTacToe.Droid
open System.Reflection
open System.Runtime.CompilerServices
// the name of the type here needs to match the name inside the ResourceDesigner attribute
type Resources = TicTacToe.Droid.Resource
[<assembly: Android.Runtime.ResourceDesigner("TicTacToe.Droid.Resources", IsApplication=true)>]
[<assembly: AssemblyTitle("TicTacToe.Droid")>]
[<assembly: AssemblyDescription("")>]
[<assembly: AssemblyConfiguration("")>]
[<assembly: AssemblyCompany("")>]
[<assembly: AssemblyProduct("")>]
[<assembly: AssemblyCopyright("")>]
[<assembly: AssemblyTrademark("")>]
// The assembly version has the format {Major}.{Minor}.{Build}.{Revision}
[<assembly: AssemblyVersion("1.0.0.0")>]
//[<assembly: AssemblyDelaySign(false)>]
//[<assembly: AssemblyKeyFile("")>]
()

Просмотреть файл

@ -186,12 +186,10 @@ type App() =
Application.Current.MainPage.DisplayAlert("Game over", msg, "OK") |> ignore
let page =
Program.mkSimple
App.init
(App.update gameOver)
(fun _ _ -> HelperPage(App.viewAllocatedSizeFixup), [], App.view)
Program.mkSimple App.init (App.update gameOver) App.view
|> Program.withConsoleTrace
|> Program.runDynamicView
|> Program.withDynamicView
|> Program.run
let mainPage = NavigationPage(page, BarBackgroundColor = Color.LightBlue, BarTextColor = Color.Black)
do base.MainPage <- mainPage

Просмотреть файл

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="FSharp.Control.AsyncSeq" version="2.0.21" targetFramework="monoandroid71" />
<package id="FSharp.Core" version="4.3.4" targetFramework="monoandroid71" />
</packages>

Просмотреть файл

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="FSharp.Control.AsyncSeq" version="2.0.21" targetFramework="monoandroid71" />
<package id="FSharp.Core" version="4.3.4" targetFramework="monoandroid71" />
</packages>