Search code examples
cocoamonococoa-bindingsmonomac

Cocoa bindings only update when window focus changes


I am using MonoMac to build a desktop download manager for Mac in C#.

My XIB has a Table View, whose columns are bound to an NSArrayController. The array controller is connected to my Main Window Controller through an IBOutlet. The array holds a bunch of HttpDownload objects, which derive from NSObject. These HttpDownload objects contain properties such as TotalSize, TotalDownloaded, Bandwidth, etc. I have decorated these properties with an [Export] attribute.

In the controller I add some HttpDownload objects to the NSArrayController using the AddObject method. A background process, started with Task.Factory.StartNew() begins the download asynchronously and updates the bound properties such as TotalDownloaded and Bandwidth as data is received.

I can see these new values being reflected in the Table View, but only once I've "forced" a UI update, for instance by causing the window to lose focus, gain focus, or by clicking on a button within the window.

I have tried setting Continuously Updates Value in IB, but this makes no difference (and reading the docs, I didn't think it should).

Does anyone know to make the UI update the bound values in "real time", instead of only when a window event occurs?


Solution

  • I figured this out shortly after I posted this question.

    It seems that we need to manually call WillChangeValue() and DidChangeValue() for at least one of the keys that are being updated, for instance, when I updated the total downloaded:

    WillChangeValue("DownloadedBytes");
    DownloadedBytes += bytesRead;
    DidChangeValue("DownloadedBytes");
    

    In my case, calling these methods for just one of the updated keys seems to be enough to force an update of all the bound values.

    For reference, in Objective-C these selectors are called [self willChangeValueForKey:@"keyname"] and [self didChangeValueForKey:@"keyname"].