如何在viewmodel上使用DelegateCommand?

Sco*_*rod 8 f#

有没有关于如何在用F#编写的viewmodel上调用DelegateCommand的示例?

我已经找到了一个DelegateCommand执行下面的代码在这里:

type DelegateCommand<a>(execute : 'a -> unit, ?canExecute : 'a  ->  bool) =
  let event = Event<_,_>()
  interface ICommand with
    member this.CanExecute(param : obj) =
      if canExecute.IsSome then
        canExecute.Value(param :> 'a)
      else true
    member this.Execute (param : obj) =
      execute(param :> 'a)
Run Code Online (Sandbox Code Playgroud)

但是,作为F#的新手,我不确定是否应该使用此实现,或者我是否应该利用其他方法.

这是我想知道如何执行DelegateCommand后要执行的测试:

module CreateProfileViewModel.Tests

open FsUnit
open NUnit.Framework
open CreateProfile.UILogic

[<Test>]
let ``create profile`` () =

    // Setup
    let viewModel = ViewModel()
    viewModel.FirstName <- "Scott"
    viewModel.LastName <- "Nimrod"

    // Test
    viewModel.Submit.Execute();

    // Verify
    let expected = false // TODO - implement some state-change
    expected |> should equal true
Run Code Online (Sandbox Code Playgroud)

我的viewmodel如下:

module CreateProfile

open Core.UILogic

type ViewModel() =
    inherit ViewModelBase()
    let mutable firstName = ""
    let mutable lastName = ""

    member this.FirstName
        with get() = firstName 
        and set(value) =
            firstName <- value
            base.NotifyPropertyChanged(<@ this.FirstName @>)

    member this.LastName
        with get() = lastName 
        and set(value) =
            lastName <- value
            base.NotifyPropertyChanged(<@ this.LastName @>)
Run Code Online (Sandbox Code Playgroud)

我有以下base-viewmodel:

module Core.UILogic

open System.ComponentModel
open Microsoft.FSharp.Quotations.Patterns

type ViewModelBase () =
    let propertyChanged = 
        Event<PropertyChangedEventHandler,PropertyChangedEventArgs>()

    let getPropertyName = function 
        | PropertyGet(_,pi,_) -> pi.Name
        | _ -> invalidOp "Expecting property getter expression"

    interface INotifyPropertyChanged with
        [<CLIEvent>]
        member this.PropertyChanged = propertyChanged.Publish

    member private this.NotifyPropertyChanged propertyName = 
        propertyChanged.Trigger(this,PropertyChangedEventArgs(propertyName))

    member this.NotifyPropertyChanged quotation = 
        quotation |> getPropertyName |> this.NotifyPropertyChanged
Run Code Online (Sandbox Code Playgroud)

更新:

我已将F#的MVVM项目模板中定义的RelayCommand修改为以下内容:

module UILogic.Interaction

open System
open System.Windows
open System.Windows.Input
open System.ComponentModel

type DelegateCommand (action:(obj -> unit), canExecute:(obj -> bool)) =
    let event = new DelegateEvent<EventHandler>()
    interface ICommand with
        [<CLIEvent>]
        member this.CanExecuteChanged = event.Publish
        member this.CanExecute arg = canExecute(arg)
        member this.Execute arg = action(arg)
Run Code Online (Sandbox Code Playgroud)

然后我更新了我的viewmodel,如下所示:

module CreateProfile.UILogic

open UILogic.State
open UILogic.Interaction

type ViewModel() =
    inherit ViewModelBase()

    let mutable _firstName = ""
    let mutable _lastName = ""
    let mutable _submitted = false

    member this.FirstName
        with get() = _firstName 
        and set(value) =
            _firstName <- value
            base.NotifyPropertyChanged(<@ this.FirstName @>)

    member this.LastName
        with get() = _lastName 
        and set(value) =
            _lastName <- value
            base.NotifyPropertyChanged(<@ this.LastName @>)

    member this.IsSubmitted
        with get() = _submitted
        and set(value) = _submitted <- value

    member this.Submit =
        new DelegateCommand ((fun _ -> this.IsSubmitted <- true), (fun _ -> true))
Run Code Online (Sandbox Code Playgroud)

但是,我不确定如何在Submit(DelegateCommand)上调用Execute函数:

module CreateProfileViewModel.Tests

open FsUnit
open NUnit.Framework
open UILogic.State
open CreateProfile.UILogic

[<Test>]
let ``create profile`` () =

    // Setup
    let viewModel = ViewModel()
    viewModel.FirstName <- "Scott"
    viewModel.LastName <- "Nimrod"

    // Test
    ignore viewModel.Submit.Execute(); // How to invoke execute?

    // Verify
    viewModel.IsSubmitted |> should equal true
Run Code Online (Sandbox Code Playgroud)

我知道这是微不足道的,但老实说,我不知道如何做到这一点.

有什么建议?

Mar*_*ann 3

将实现更改Submit为:

member this.Submit =
    DelegateCommand ((fun _ -> this.IsSubmitted <- true), (fun _ -> true)) :> ICommand
Run Code Online (Sandbox Code Playgroud)

并这样称呼它:

viewModel.Submit.Execute() |> ignore
Run Code Online (Sandbox Code Playgroud)

重要的变化是该Submit方法的返回类型现在ICommandDelegateCommand. 这是由于使用了 upcast 运算符:>

在 F# 中,所有接口均显式实现。这意味着虽然DelegateCommand实现了ICommand,但 的方法ICommand在声明(或推断)为 的对象上不可见DelegateCommandICommand另一方面,当值被声明(或推断)为 类型时,只有 的成员ICommand可用。