F#wpf async命令完成状态

时间:2016-02-22 12:44:40

标签: wpf xaml mvvm f#

我一直在使用F#Viewmodule试验异步命令。问题是当我单击按钮时,命令执行,但之后按钮保持禁用状态。

的Xaml:

<Button Content="start async worker" Command="{Binding StartAsyncCommand}" />

视图模型:

type MainViewModel() as me = 
  inherit ViewModelBase()
//...
member __.StartAsyncCommand = me.Factory.CommandAsync(fun _ -> async { return () } )

我做错了什么?

修改

感谢@FoggyFinder,我们确定问题实际上是App.fs文件:

open System
open FsXaml
open System.Windows

type MainWindow = XAML< "MainWindow.xaml">

[<STAThread>]
[<EntryPoint>]
let main argv = 
  Application().Run(MainWindow().Root)

创建基本上空的App.xaml并从这样开始:

module main

open System
open FsXaml

type App = XAML<"App.xaml">

[<STAThread>]
[<EntryPoint>]
let main argv =
    App().Root.Run()

修好了。如果有人知道对此的解释,请不要犹豫,提供它。

3 个答案:

答案 0 :(得分:2)

我使用了异步命令,但这个问题从未出现过。我试图重现你的代码 - 一切正常。你确定你提供了完整的代码吗?

尝试运行代码: 的.xaml:

<Window.DataContext>
    <local:MainViewModel/>
</Window.DataContext>
<Grid>
    <Button Content="start async worker" Command="{Binding StartAsyncCommand}" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5" />
    <TextBlock Text="{Binding Count}" Margin="5" HorizontalAlignment="Right"  VerticalAlignment="Top"></TextBlock>
</Grid>

视图模型:

type MainViewModel() as me = 
    inherit ViewModelBase()    

    let count = me.Factory.Backing(<@ me.Count @>, 0)

    member __.StartAsyncCommand = me.Factory.CommandAsync(fun _ -> async { count.Value <- count.Value + 1 })
    member __.Count with get() = count.Value

关于

之间的区别
let dosomething _ = async { return () }
member __.StartAsyncCommand = me.Factory.CommandAsync(dosomething)

和:

member __.StartAsyncCommand = me.Factory.CommandAsync(fun _ -> async { return () } )
看看这个答案: http://chat.stackoverflow.com/transcript/message/26511092#26511092

答案 1 :(得分:2)

  

我做错了什么?

问题是构建ViewModel层时没有SynchronizationContext,这意味着将内容推回到UI上下文的内部代码无法正常工作。

您可以在致电Application.Run()之前在入口点的开头添加以下内容来解决此问题:

if SynchronizationContext.Current = null then
    DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher)
    |> SynchronizationContext.SetSynchronizationContext

这将确保创建Dispatcher并安装有效的SynchronizationContext,并且可能会为您解决问题。

答案 2 :(得分:1)

简单的解决方法是使用交互触发器:

<Button>
    <ia:Interaction.Triggers>
        <ia:EventTrigger EventName="Click">
            <fsx:EventToCommand Command="{Binding StartAsyncCommand}" />
        </ia:EventTrigger>
    </ia:Interaction.Triggers>
</Button>