Home > other >  Passing an object to an event with given signature
Passing an object to an event with given signature

Time:09-08

My goal is to pass an object to an event. The event has a given signature I can't change (so I can't define my own EventArgs). Specifically, I am talking about a passkey that is required for a Bluetooth pairing event, but the question is a general one. I subscribe to the event before starting the pairing procedure:

public async Task MyPairAsync(Device device)
{
    var bluetoothLEDevice = await BluetoothLEDevice.FromBluetoothAddressAsync(device.Id);
    DeviceInformationCustomPairing customPairing = bluetoothLEDevice.DeviceInformation.Pairing.Custom;
    customPairing.PairingRequested  = CustomPairing_PairingRequested;
    var result = await customPairing.PairAsync(DevicePairingKinds.ProvidePin);
    // Do more stuff (evaluate result etc.)...
}

The class "Device" contains the Id of the BLE device and the passkey:

public class Device
{
    public ulong Id { get; }
    public string Passkey { get; private set; }

    public Device(ulong id, string passkey)
    {
        Id = id;
        Passkey = passkey;
    }
}

The signature of the PairingRequested event is fixed, so CustomPairing_PairingRequested needs to follow that signature:

private void CustomPairing_PairingRequested(DeviceInformationCustomPairing sender, DevicePairingRequestedEventArgs args)
{
    args.Accept(device.Passkey);  // This doesn't work, since device is unknown in this context.
}

The class DevicePairingRequestedEventArgs is sealed, so I can't extend a class from it that could contain a Device instance.

How can I pass the Device object (and with it, the passkey information) to the CustomPairing_PairingRequested event? I could of course define a global Device variable, set it to the current Device object in MyPairAsync() and read it in the event, but that seems very ugly. Is there a better option to do this?

CodePudding user response:

What about wrapping all the publishing-subscribeing code along with the device instance?..

Replace

customPairing.PairingRequested  = CustomPairing_PairingRequested;
var result = await customPairing.PairAsync(DevicePairingKinds.ProvidePin);
// Do more stuff (evaluate result etc.)...

with

var prWrapper = new PairingRequestWrapper(device);
var result = await prWrapper.PairAsync(customPairing, () => { 
    // doing some stuff after `args.Accept(device.Passkey)`
});
// Do more stuff (evaluate result etc.)...

Where PairingRequestWrapper is

public class PairingRequestWrapper{
    
    private Device device;
    
    public PairingRequestWrapper(Device d){
        device = d;
    }

    private Action callbackAction;

    // I mean, the result type
    public async Task<Result> PairAsync(DeviceInformationCustomPairing customPairing, Action callbackAction = null){
        this.callbackAction = callbackAction;
        customPairing.PairingRequested  = CustomPairing_PairingRequested;
        return await customPairing.PairAsync(DevicePairingKinds.ProvidePin);
    }
    
    // no need to `CustomPairing_PairingRequested` in the original code.
    private void CustomPairing_PairingRequested(DeviceInformationCustomPairing sender, DevicePairingRequestedEventArgs args)
    {
        args.Accept(device.Passkey);
        callbackAction?.Invoke();
    }
}

CodePudding user response:

Have you tried to define extension method on event handler?

public static void RaiseEvent(this EventHandler @event, DeviceInformationCustomPairing sender, DevicePairingRequestedEventArgs e, Device device) 
{ 
  if (@event != null) 
  { 
    e.Accept(device.PassKey); 
    @event(sender, e); 
  } 
} 
  • Related