我的绑定 属性 之一和我的 ActivityIndicator 之间的问题
Problem between one of my binded property and my ActivityIndicator
我在使用 F# 方面还很陌生,我正在尝试用 F# 重写一个完整的 C# 库。我有一个 Xamarin.forms 项目,其中的 C# 库包含我所有的视图,我的目标是拥有另外两个库,一个在 C# 中,一个在 F# 中,每个库都包含相同的 ViewModel。
一切正常,除了我的 属性.
中的最后一件小事
我的应用程序很简单,它只是让用户登录 Facebook,然后检索他在 Facebook Wall 上发布的所有帖子,并使用 ListView 显示这些帖子。在处理检索工作时,我想 运行 一个 ActivityIndicator,以便用户可以看到应用程序正在运行。
这是他的我的 ActivityIndicator 和我的 ListView 在我的 view.xaml :
<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# class :
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
所以我在我的视图中的 OnAppearing() 方法中执行了 SetData() 函数,我的 FacebookProfile 和 PostsDb 数据很好地绑定到我的 ListView 并且它显示正确。
问题是当它通过 SetData() 时,我的 ActivityIndicator 从未出现过。
但是,如果我删除 this.IsLoading <- false 行,它会正确显示(并且不会明显消失)
在我的调试控制台中,我没有绑定错误,即使在调试模式下,我也看到我的 IsLoading 属性 已更改。
我只想说,我知道以这种方式使用 F# 并不正确,而且会产生难看的 F# 代码,但这只是使用 F# 的测试 class。
我怀疑你的问题是这 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
我在使用 F# 方面还很陌生,我正在尝试用 F# 重写一个完整的 C# 库。我有一个 Xamarin.forms 项目,其中的 C# 库包含我所有的视图,我的目标是拥有另外两个库,一个在 C# 中,一个在 F# 中,每个库都包含相同的 ViewModel。 一切正常,除了我的 属性.
中的最后一件小事我的应用程序很简单,它只是让用户登录 Facebook,然后检索他在 Facebook Wall 上发布的所有帖子,并使用 ListView 显示这些帖子。在处理检索工作时,我想 运行 一个 ActivityIndicator,以便用户可以看到应用程序正在运行。 这是他的我的 ActivityIndicator 和我的 ListView 在我的 view.xaml :
<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# class :
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
所以我在我的视图中的 OnAppearing() 方法中执行了 SetData() 函数,我的 FacebookProfile 和 PostsDb 数据很好地绑定到我的 ListView 并且它显示正确。 问题是当它通过 SetData() 时,我的 ActivityIndicator 从未出现过。 但是,如果我删除 this.IsLoading <- false 行,它会正确显示(并且不会明显消失) 在我的调试控制台中,我没有绑定错误,即使在调试模式下,我也看到我的 IsLoading 属性 已更改。
我只想说,我知道以这种方式使用 F# 并不正确,而且会产生难看的 F# 代码,但这只是使用 F# 的测试 class。
我怀疑你的问题是这 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