Xamarin Mac KVO 模型绑定 - 更改触发两次

Xamarin Mac KVO model bindings - change fires twice

我正在尝试在 Xamarin Mac 桌面应用程序中实现 KVO 绑定。 我已按照文档进行操作,它正在运行,但绑定似乎每次都会触发 2 个更改事件!

如果我用这样的绑定创建一个 KVO 模型...

    private int _MyVal;
    [Export("MyVal")]
    public int MyVal 
    { 
        get { return _MyVal; }
        set 
        { 
            WillChangeValue("MyVal"); 
            this._MyVal = value; 
            DidChangeValue("MyVal"); 
        }
    }

并在 bindings 部分下的 Xcode 中绑定一个控件到路径 self.SettingsModel.MyValue

看起来一切正常,控件显示模型值,更改模型值以编程方式更新控件,更改控件更新模型值。

但是,它运行了两次更改事件。

我正在监听变化,因此我可以用值点击 API。

SettingsModel.AddObserver(this, (NSString)key, NSKeyValueObservingOptions.New, this.Handle);

然后……

 public override void ObserveValue(NSString keyPath, NSObject ofObject, NSDictionary change, IntPtr context)
    {
        switch (keyPath)
        {
            case "MyValue":

            // CODE HERE THAT UPDATES AN API WITH THE VALUE                 
            // But this handler fires twice.


            break;
        }
    }

我不确定是 Xamarin 还是 XCode 导致了双重触发。

有趣的是,如果您没有指定 Xcode WillChangeValueDidChangeValue 方法,那么它不会触发两次 - 就好像 Xamarin 已经自动触发了一次更改。但是,当以编程方式更新模型值时,它不再触发更改...

[Export("MyVal")]
public int MyVal { get; set }

以上内容适用于 Xcode 控件,它们将更新模型并触发更改事件。

但以编程方式更新它

this.SettingsModel.MyVal = 1;

不触发更改事件。

关于如何停止触发 2 个更改事件的任何想法都非常令人困惑,因为我不想每次都点击 API 两次!

当它触发两次时,第一次的堆栈跟踪(删节)有...

MainViewController.ObserveValue
ObjCRuntime.Messaging.void_objc_msgSendSuper_IntPtr()
Foundation.NSObject.DidChangeValue(string forKey)
CameraSettingsModel.set_MyValue(int value)
AppKit.NSApplication.NSApplicationMain() 
AppKit.NSApplication.Main(string[] args) 
MainClass.Main(string[] args) 

看起来不错,但是第二个...

MainViewController.ObserveValue
AppKit.NSApplication.NSApplicationMain()
AppKit.NSApplication.Main(string[] args) 
MainClass.Main(string[] args)

没有提到触发事件的设置模型

你正在打这个 - Receiving 2 KVO notifications for a single KVC change

并且需要覆盖它出现的 AutomaticallyNotifiesObserversForKey。

Cocoa 是 "doing you a favor" 通过为您发送通知,这很棒,除非您有托管版本也发送通知。

看起来像这样:

    [Export ("automaticallyNotifiesObserversForKey:")]
    public static new bool AutomaticallyNotifiesObserversForKey (string key) => false;

    bool _checkValue;

    [Export("CheckValue")]
    public bool CheckValue
    {
        get { return _checkValue; }
        set
        {
            WillChangeValue("CheckValue");
            _checkValue = value;
            DidChangeValue("CheckValue");
        }
    }

    public override void ViewDidLoad ()
    {
        base.ViewDidLoad();

        this.AddObserver("CheckValue", NSKeyValueObservingOptions.New, o =>
        {
            Console.WriteLine($"Observer triggered for {o}");
        });

        CheckValue = false;

}