In Cocoa, some classes offers a way to notify a delegate for several actions by implementing an informal protocol. One of the most known class that offers this system is NSApplication : the delegate can be notify when the application is launched, has started or if it must close when the last windows is closed.

In .NET, a similar behavior can be achieved through the use of events. The Monobjc bridge offers a way to integrate the Cocoa delegation with their notifications in a simplier way by leveraging the power of the .NET events. Here is a list of some classes that allow the use of events in addition to the use of the Cocoa delegate (for more class, see the API Reference):

  • NSAlert
  • NSAnimation
  • NSApplication
  • NSSound
  • NSWindow

Examples

The Objective-C syntax is very straightfoward. The callback must be exposed as an Objective-C message and both the instance and the selector are passed when calling the sheet method.

The following examples shows how to listen for specific events for the NSSpeechSynthesizer class:

[ObjectiveCMessage("awakeFromNib")]
public void AwakeFromNib()
{
    this._speechSynthesizer = new NSSpeechSynthesizer();
    this._speechSynthesizer.Delegate = this;
}

[ObjectiveCMessage("speechSynthesizer:willSpeakPhoneme:")] 
public void SpeechSynthesizerWillSpeakPhoneme(NSSpeechSynthesizer sender, short phonemeOpcode)
{
    ...
}

[ObjectiveCMessage("speechSynthesizer:didFinishSpeaking:")] 
public void SpeechSynthesizerDidFinishSpeaking(NSSpeechSynthesizer sender, bool finishedSpeaking)
{
    ...
}

[ObjectiveCMessage("speechSynthesizer:willSpeakWord:ofString:")] 
public void SpeechSynthesizerWillSpeakWordOfString(NSSpeechSynthesizer sender, NSRange characterRange, NSString str)
{
    ...
}

The .NET syntax is less straightfoward. The delegate methods do not need to be exposed and but the delegate assignment is a bit different.

[ObjectiveCMessage("awakeFromNib")]
public void AwakeFromNib()
{
    this.webView.SetFrameLoadDelegate(d =>
                                          {
                                              d.WebViewDidStartProvisionalLoadForFrame += this.WebViewDidStartProvisionalLoadForFrame;
                                              d.WebViewDidFinishLoadForFrame += this.WebViewDidFinishLoadForFrame;
                                              d.WebViewDidReceiveTitleForFrame += this.WebViewDidReceiveTitleForFrame;
                                          });
}

private void WebViewDidStartProvisionalLoadForFrame(WebView sender, WebFrame frame)
{
    ...
}

private void WebViewDidFinishLoadForFrame(WebView sender, WebFrame frame)
{
    ...
}

private void WebViewDidReceiveTitleForFrame(WebView sender, NSString title, WebFrame frame)
{
    ...
}

Why such a weird assignment ?

In Objective C, the delegate is sometimes probed for the messages it supports when it is assigned. In order to match this behavior, the Monobjc bridge uses lambda expresion to be sure that all the event wiring is done before the delegate assignment.