在Xamarin.Forms中使用F#异步支持无法观察页面导航

时间:2018-10-24 04:42:10

标签: xamarin.forms f#

我无法观察页面导航。

命令:

member x.AddBankcard =    DelegateCommand( (fun _ -> async { do! navigate() 
                                                           } |> Async.RunSynchronously 
                                                             |> ignore ) ,
                                            fun _ -> true) :> ICommand

发布导航请求:

let navigate() =

    account 
     |> PageRequest.AddBankcard 
     |> broadcastToAsync pageRequesthandlers     

通知订阅者请求:

let broadcastToAsync<'a> (handlers:(list<'a -> Async<unit>>)) (msg:'a) : Async<unit> =

    async { handlers |> List.map (fun handle -> async { do! handle msg }) |> ignore }

手柄导航:

let handle = function
    | PageRequest.AddBankcard _ ->
        page |> function 
        | :? UI.AddBankcard as pageRequest ->
            ...
            async { do! navigationPage.PushAsync(pageRequest) |> Async.AwaitTask }

        | _ -> async { () }
    | _ -> async { () }

注意:

  1. 不进行页面导航。

  2. 我没有收到任何例外。

  3. 我在输出窗口中看不到任何线索

  4. 我的直觉是我没有正确使用异步。

    异步{做! navigationPage.PushAsync(pageRequest)|> Async.AwaitTask}

已更新

我还尝试了以下方法:

let navigationPage = (app:?>Application).MainPage:?>NavigationPage

let navigate () = async  {
    do! navigationPage.PushAsync(pageRequest) |> awaitTask
}

navigate() |> Async.RunSynchronously |> ignore

Here's the source code

3 个答案:

答案 0 :(得分:2)

仅当异步/任务操作完成后必须执行代码时,才需要async {...}块。

对于导航,此后通常无事可做(某些MVVM框架除外)。ignore是必需的,因为函数签名要求返回单元,并且导航方法返回{{1} }。在C#中,Task在被调用时启动,而F#中的Task块则不在。

以下代码是一个非常简单的导航示例,无需使用async关键字或async等。

Async.AwaitTask

答案 1 :(得分:1)

我可以告诉你,函数broadcastToAsync并没有真正执行任何操作:

let broadcastToAsync<'a> (handlers:(list<'a -> Async<unit>>)) (msg:'a) : Async<unit> =
    async { handlers |> List.map (fun handle -> async { do! handle msg }) |> ignore }

原因是它先创建了async个列表,然后又ignore个列表。

我建议您将List.map更改为List.iter,删除|> ignore并调用Async.RunSynchronously

let broadcastToAsync handlers msg =
    handlers |> List.iter (fun handle -> handle msg |> Async.RunSynchronously )

"msg" |> broadcastToAsync [ 
        fun msg -> async { printfn "1: %A" msg}
        fun msg -> async { printfn "2: %A" msg} ] 

// 1: "msg"
// 2: "msg"

答案 2 :(得分:0)

以下代码有效:

let navigationPage = (app:?>Application).MainPage:?>NavigationPage
navigationPage.PushAsync(pageRequest) |> Async.AwaitTask |> ignore

以下是一些将页面弹出堆栈的代码:

app |> function
| :? Application as xForms -> 

let navigationPage = xForms.MainPage:?>NavigationPage
navigationPage.PopAsync() |> Async.AwaitTask |> ignore