我在使用F#方面还很陌生,我想用F#重写一个完整的C#库。我有一个Xamarin.forms项目,其中一个C#库包含我所有的视图,我的目标是拥有另外两个视图库,一个用C#编写,一个用F#编写,每个库都包含相同的ViewModel。 一切正常,除了我财产中的最后一件小事。
我的应用程序很简单,它只是将用户登录到Facebook,然后检索他在Facebook墙上张贴的所有帖子,并使用ListView进行显示。在进行检索工作时,我想运行一个ActivityIndicator,以便用户可以看到该应用程序正在运行。 这是他在view.xaml中的我的ActivityIndicator和ListView:
<ActivityIndicator IsVisible="{Binding IsLoading}" IsRunning="{Binding IsLoading}"
VerticalOptions="Center"
HorizontalOptions="Center"
Grid.Row="0"
Grid.Column="0"
Scale="4"
Color="#0078FF"/>
<ListView x:Name="PostsView"
ItemsSource="{Binding PostsDb}"
ItemTapped="PostsView_ItemTapped"
HasUnevenRows ="True"
BackgroundColor="LightGray"
IsPullToRefreshEnabled="True"
RefreshCommand="{Binding RefreshCommand}"
IsRefreshing="{Binding IsRefreshing}"
Grid.Row="0"
Grid.Column="0"
IsVisible="{Binding IsLoading, Converter={StaticResource ReverseBool}}">
这是我的F#课:
type FacebookViewModel(navigationService: INavigationService) =
inherit ViewModelBase()
let mutable facebookProfile = new FacebookProfileDbObject()
let mutable postsDb = new List<FacebookPostsDbObject>()
let mutable isLoading = false
member this.FacebookProfile
with get() = facebookProfile
and set(value) =
facebookProfile <- value
base.NotifyPropertyChanged(<@ this.FacebookProfile @>)
member this.PostsDb
with get() = postsDb
and set(value) =
postsDb <- value
base.NotifyPropertyChanged(<@ this.PostsDb @>)
member this.IsLoading
with get() = isLoading
and set(value) =
isLoading <- value
base.NotifyPropertyChanged(<@ this.IsLoading @>)
member this.SetData() =
this.IsLoading <- true
this.FacebookProfile <- GetProfileData() |> Async.RunSynchronously
this.PostsDb <- GetPostData() |> Async.RunSynchronously
this.IsLoading <- false
因此,我在View的OnAppearing()方法中执行SetData()函数,并且我的FacebookProfile和PostsDb数据已很好地绑定到ListView上,并且可以正确显示。 问题在于,当它通过SetData()传递时,我的ActivityIndicator从未出现过。 但是,如果我删除this.IsLoading <-false行,它将正确显示(并且永远不会消失) 在我的调试控制台中,我没有任何绑定错误,即使在调试模式下,我也发现IsLoading属性已被更改。
我只想说我知道以这种方式使用F#并不是真的正确,并且会产生难看的F#代码,但这只是使用F#类的测试。
答案 0 :(得分:0)
我怀疑您的问题是这4行都是同步执行的,因此即使您在一开始就正确this.IsLoading <- true
,UI也始终不会收到该消息,因为您的执行实际上已锁定了这4行:
this.IsLoading <- true
this.FacebookProfile <- GetProfileData() |> Async.RunSynchronously
this.PostsDb <- GetPostData() |> Async.RunSynchronously
this.IsLoading <- false
您需要通过首先创建异步工作流来找到一种异步运行它们的方法:
async {
this.IsLoading <- true
let! profileData = GetProfileData()
let! postData = GetPostData()
this.FacebookProfile <- profileData
this.PostsDb <- postData
this.IsLoading <- false
}
然后确定您如何处理该工作流程,如果调用GetData()的代码可以处理任务,则可以将其传递到startAsTask
:
member this.SetDataAsync() =
async {
// copy code from above
}
|> Async.startAsTask