难以绑定 iOS 不带参数的委托方法

Difficulty binding iOS delegate method without parameters

为 Xamarin 绑定 iOS lib.a 时,出现以下错误:

btouch: The delegate method Device.SomeDeviceDelegate.CaptureComplete needs to take at least one parameter (BI1003)

已生成绑定 Objective Sharpie

namespace Device 
{   

    // @protocol SomeDeviceDelegate <NSObject>
    [Protocol, Model, Preserve]
    [BaseType(typeof(NSObject))]
    interface SomeDeviceDelegate
    {
        // @optional -(void)CaptureComplete;
        [Export("CaptureComplete")]
        void CaptureComplete();
    }

    // @interface SomeDevice : NSObject
    [Protocol, Model, Preserve]
    [BaseType(typeof(NSObject), Delegates = new[] { "WeakDelegate" }, Events = new[] { typeof(SomeDeviceDelegate) })]
    interface SomeDevice
    {
        [Wrap("WeakDelegate")]
        SomeDeviceDelegate Delegate { get; set; }

        // @property (assign, nonatomic) id<SomeDeviceDelegate> delegate;
        [NullAllowed, Export("delegate", ArgumentSemantic.Assign)]
        SomeDeviceDelegate WeakDelegate { get; set; }
    }

}

注意。我已将名称更改为 SomeDevice 以隐藏 hardware/device 名称 (NDA)。

编译器抱怨 // @optional -(void)CaptureComplete; 和相应的绑定 CaptureComplete() 没有参数,并且至少需要一个。

问:我需要做什么来绑定这个委托?

我已经尝试了 Binding Types Reference Guide 并尝试应用

更新

我误解了 NoDefaultValueDefaultValueFromArgument 属性,当委托 return 是一个值(例如 bool)时使用它们作为 return 干扰使用事件的 Xamarin 包装。

"CaptureComplete:" 可能正在等待发件人?

我找到了解决方案。

注意:这次我没有更改名称,因为它使答案不太清楚。

处理 ObjC 委托的首选方法是将它们公开为事件,例如

// @interface ICBarCodeReader : ICISMPDevice
[DisableDefaultCtor]
[BaseType(typeof(ICISMPDevice), Delegates = new[] { "WeakDelegate" }, Events = new[] { typeof(ICBarCodeReaderDelegate) }))]
public interface ICBarCodeReader
{
    [Wrap("WeakDelegate")]
    ICBarCodeReaderDelegate Delegate { get; set; }

    // @property (assign, nonatomic) id<ICISMPDeviceDelegate,ICBarCodeReaderDelegate> delegate;
    [NullAllowed, Export("delegate", ArgumentSemantic.Assign)]
    ICBarCodeReaderDelegate WeakDelegate { get; set; }
}

BaseType 的 Delegate 和 Events 参数,生成包装 ICBarCodeReaderDelegate 上每个方法的代码。

// @protocol ICBarCodeReaderDelegate
[Protocol, Model, Preserve]
[BaseType(typeof(ICISMPDeviceDelegate))]
public interface ICBarCodeReaderDelegate
{
    // @required -(void)barcodeData:(id)data ofType:(int)type;
    [Abstract]
    [Export("barcodeData:ofType:")]
    [EventArgs("BarcodeData")]
    void BarcodeData(string data, BarCodeSymbologies type);

    // @required -(void)configurationRequest;
    [Abstract]
    [Export("configurationRequest")]
    void ConfigurationRequest();
}

它允许你在你的项目中做:

public void Init()
{
    _sharedBarCodeReader.BarcodeData += OnBarcodeData;
}

private void OnBarcodeData(object sender, BarcodeDataEventArgs e)
{
    var barcode = Convert.ToString(sender); // this maps to string data
    //BarCodeSymbologies is in BarcodeDataEventArgs

    var handler = BarCodeData;
    if (handler != null)
        handler(this, barcode);
}

但是,如 btouch 错误消息所述,当方法没有参数时,此方法会失败。

我发现的另一种方法(现在看起来简单明了)是不将委托包装为事件,例如

// @interface ICBarCodeReader : ICISMPDevice
[DisableDefaultCtor]
[BaseType(typeof(ICISMPDevice))]
public interface ICBarCodeReader
{
    [Wrap("WeakDelegate")]
    ICBarCodeReaderDelegate Delegate { get; set; }

    // @property (assign, nonatomic) id<ICISMPDeviceDelegate,ICBarCodeReaderDelegate> delegate;
    [NullAllowed, Export("delegate", ArgumentSemantic.Assign)]
    ICBarCodeReaderDelegate WeakDelegate { get; set; }
}

而是创建 Delegate 接口的实现。

例如

public void Init()
{
    _sharedBarCodeReader.Delegate = new BarCodeReaderDelegate(this);
}

private class BarCodeReaderDelegate : ICBarCodeReaderDelegate
{
    public BarCodeReaderDelegate(BarCodeScanner barCodeScanner)
    {
        _barCodeScanner = barCodeScanner;
    }

    public override void BarcodeData(string data, BarCodeSymbologies type)
    {
        var handler = _barCodeScanner.BarCodeData;
        if (handler != null)
            handler(this, data);
    }

    public override void ConfigurationRequest() { }

    private readonly BarCodeScanner _barCodeScanner;
}