【问题标题】:Is it possible to implement INotifyPropertyChanged as a Type Extension in F#是否可以在 F# 中将 INotifyPropertyChanged 实现为类型扩展
【发布时间】:2014-10-27 17:08:44
【问题描述】:

在 C# 中,您可以实现基于 PropertyChangedEventHandler 的扩展方法,如下所示:

  static class VMExts
  {
    public static void RaisePropertyChanged(this PropertyChangedEventHandler handler, object sender, string propName)
    {
      if(handler != null)
      {
        handler(sender, new PropertyChangedEventArgs(propName));
      }
    }
  }

可以这样调用:

  class VM : INotifyPropertyChanged
  {
    private string _someText;

    public event PropertyChangedEventHandler PropertyChanged;

    public string SomeText
    {
      get { return _someText; }
      set
      {
        _someText = value;
        PropertyChanged.RaisePropertyChanged(this, "SomeText");
      }
    }
  }

我一直试图在 F# 中实现类似的功能,但无法弄清楚语法。 通过继承一些 ViewModelBase 样式类(例如http://www.fssnip.net/2x)显然很容易实现这一点,但如果有一个扩展方法真的很好。

所以,给定这个类:

  type ViewModelBase() =
    let mutable _someText = ""
    let propertyChanged = Event<_, _>()

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

    member x.SomeText 
      with get() = _someText
      and set(value) = 
        _someText <- value
        (x :> INotifyPropertyChanged).PropertyChanged.RaisePropertyChanged("SomeText")

我试过了:

  type PropertyChangedEventHandler with
    member x.RaisePropertyChanged(sender, propName) =
      if x <> null then
        x.Invoke(sender, PropertyChangedEventArgs(propName))

  open System.Runtime.CompilerServices

  [<Extension>]
  type VmExtensions() =
    [<Extension>]  
    static member inline RaisePropertyChanged(handler : PropertyChangedEventHandler, propName) =
      if handler <> null then
        handler.Invoke(handler, PropertyChangedEventArgs(propName))

我认为这些无法找到对 PropertyChanged 有效,因为 PropertyChanged 的​​类型是 IEvent,而我已经扩展了 PropertyChangedEventHandler 类型。

于是我尝试了:

  type IEvent<PropertyChangedEventHandler, PropertyChangedEventArgs> with
    member x.RaisePropertyChanged(sender, propName) =
      if x <> null then
        x.Invoke(sender, PropertyChangedEventArgs(propName))

但是编译器不喜欢使用 IEvent

  [<Extension>]
  type VmExtensions() =
    [<Extension>]  
    static member inline RaisePropertyChanged(handler : IEvent<PropertyChangedEventHandler, PropertyChangedEventArgs>, propName) =
//      if handler <> null then
        handler.Invoke(handler, PropertyChangedEventArgs(propName))

但是 IEvent 真的只有一个订阅方法

谢谢

【问题讨论】:

    标签: mvvm f# extension-methods inotifypropertychanged


    【解决方案1】:

    您可以通过Trigger 方法引发事件,该方法在Event(而不是IEvent)上定义:

    [<Extension>]
    type VmExtensions =
        [<Extension>]  
        static member inline RaisePropertyChanged
            (ev:Event<PropertyChangedEventHandler, _>, propName) =
    
            ev.Trigger(null, PropertyChangedEventArgs propName)
    

    【讨论】:

    • 啊,是的,谢谢。很遗憾,我需要强制转换在 PropertyChanged.Publish 中创建的 IEvent。我要么需要在 RaisePropertyChanged 函数中执行此操作,并在强制转换失败时引发异常,要么在我使用 INotifyPropertyChanged 的​​任何地方执行此操作。
    • 很高兴你找到了一些有用的东西。那你能检查一下答案吗?附带说明一下,我真的不明白您为什么要使用首先需要从IEvent&lt; , &gt; 转换为Event&lt; , &gt; 的方法。避免重复实现INotifyPropertyChanged 的常用解决方案是简单地从ViewModelBase 类(如您的类)继承,该类定义了某种(内部)OnNotivyPropertyChanged 方法,可以由继承者调用。它不是“惯用的”F#,但它完全没问题。从务实的角度来看。
    • 是的,你是对的。我忘记了我已经创建了 Event 并且可以访问它,所以我关于强制转换的观点是无关紧要的。使用它,我想出了一些我非常喜欢的实现方式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多