我要求UWP应用在启动应用时,在蓝牙扫描器重新通电后,或者在超出范围后又回到范围内时,要求任何已配对的蓝牙扫描器设备都拥有所有权。用户甚至不必考虑连接/声明。打开扫描仪设备并运行UWP应用程序即可。
我还没有找到任何可靠的方法或事件来自动检测蓝牙扫描器何时处于 范围内并且“准备提出索赔”。 (例如,在伸手可及的距离后,或者在打开蓝牙扫描仪设备的电源或关闭后再打开电源。)
基本上,这产生了以下代码,其中我的代码不断尝试声明DeviceWatcher检测到的任何蓝牙扫描仪。它将这样做直到成功。对于DeviceWatcher中任何无人认领的扫描仪,都会在计时器上尝试进行认领。另外,我还必须使用一种相当难看的try / catch构造来防止失败的ClaimScannerAsync()调用崩溃,因为该方法似乎不会抛出它自己的继承的Exception类。
这似乎确实有效,但是我确实想知道是否有更好的方法可以解决此问题。
是否有更好的方法来检查何时可以使用蓝牙扫描器?
请考虑蓝牙条形码扫描仪的声明过程。
(我正在粘贴我描述的代码以供参考,以及其他可能有相同要求的人)
private readonly List<BarcodeScanner> btScannerList = new List<BarcodeScanner>();
private readonly List<ClaimedBarcodeScanner> ClaimedScannerList = new List<ClaimedBarcodeScanner>();
/// <summary>
/// Function to claim scanner with retry timer in case of claim failure (used to reclaim scanner when scanner can go out/in of range or turned on/off)
/// In this case a device removed event is not fired by DeviceWatcher
/// This function is called for each bluetooth scanner detected by DeviceWatcher
/// </summary>
/// <param name="deviceId"></param>
private async void TryClaimBtScannerByDeviceId(string deviceId)
{
try
{
if (!await this.ClaimBtScannerByDeviceId(deviceId))
{
Log.Debug($"BarcodeService.TryClaimBtScannerByDeviceId Failed to reconnect, setting timer to reconnect.");
this.SetReclaimTimerForBtScanner(deviceId);
}
}
catch
{
Log.Debug($"BarcodeService.TryClaimBtScannerByDeviceId Exception while trying to reconnect (probably a timeout), setting timer to reconnect.");
this.SetReclaimTimerForBtScanner(deviceId);
}
}
private void SetReclaimTimerForBtScanner(string deviceId)
{
var timer = new System.Timers.Timer
{
Interval = 3000,
AutoReset = false
};
timer.Elapsed += delegate { this.TryClaimBtScannerByDeviceId(deviceId); };
timer.Start();
}
private async Task<bool> ClaimBtScannerByDeviceId(string deviceId)
{
var scanner = await BarcodeScanner.FromIdAsync(deviceId);
scanner.StatusUpdated += this.Scanner_StatusUpdated;
this.btScannerList.Add(scanner);
return await this.ClaimScannerAsync(scanner);
}
private void Scanner_StatusUpdated(BarcodeScanner sender, BarcodeScannerStatusUpdatedEventArgs args)
{
if (args.Status == BarcodeScannerStatus.OffOrOffline || args.Status == BarcodeScannerStatus.Offline || args.Status == BarcodeScannerStatus.Off)
{
Log.Information($"BarcodeService.DeviceWatcher StatusUpdated to off or offline, setting reclaim timer for deviceId: {sender.DeviceId} -> {args.Status}");
var deviceId = sender.DeviceId;
this.UnsetScannerByDeviceId(deviceId);
this.SetReclaimTimerForBtScanner(deviceId);
}
}
private async Task<bool> ClaimScannerAsync(BarcodeScanner scanner)
{
Log.Information($"BarcodeService.ClaimBarcodeScannerAsync() Trying to (re)claim scanner with DeviceId: {scanner.DeviceId} for exclusive use...");
// after successful creation, claim the scanner for exclusive use and enable it so that data reveived events are received.
var claimedScanner = await scanner.ClaimScannerAsync();
if (claimedScanner == null)
{
Log.Warning($"BarcodeService.ClaimBarcodeScannerAsync() Couldn't claim barcode scanner for exclusive use (deviceid {scanner.DeviceId})");
return false;
}
else
{
Log.Information($"BarcodeService.ClaimBarcodeScannerAsync() Claimed scanner for exclusive use. Setting up event handlers...");
// It is always a good idea to have a release device requested event handler. If this event is not handled, there are chances of another app can
// claim ownsership of the barcode scanner.
claimedScanner.ReleaseDeviceRequested += this.ClaimedScanner_ReleaseDeviceRequested;
// after successfully claiming, attach the datareceived event handler.
claimedScanner.DataReceived += this.ClaimedScanner_DataReceived;
// Ask the API to decode the data by default. By setting this, API will decode the raw data from the barcode scanner and
// send the ScanDataLabel and ScanDataType in the DataReceived event
claimedScanner.IsDecodeDataEnabled = true;
// enable the scanner.
// Note: If the scanner is not enabled (i.e. EnableAsync not called), attaching the event handler will not be any useful because the API will not fire the event
// if the claimedScanner has not beed Enabled
await claimedScanner.EnableAsync();
this.ClaimedScannerList.Add(claimedScanner);
Log.Information("BarcodeService.ClaimBarcodeScannerAsync() Ready to scan. Device ID: " + claimedScanner.DeviceId);
return true;
}
}
public void UnsetScannerByDeviceId(string deviceId)
{
try
{
foreach (var claimedScanner in this.ClaimedScannerList.Where(x => x.DeviceId.Equals(deviceId)).ToList())
{
this.DisposeClaimedScanner(claimedScanner);
}
foreach (var scanner in this.btScannerList.Where(x => x.DeviceId.Equals(deviceId)).ToList())
{
this.DisposeScanner(scanner);
}
}
catch
{
Log.Warning($"BarcodeService.UnsetScannerByDeviceId() Error while disposing scanner with scannerId: {deviceId}");
}
}
private void DisposeScanner(BarcodeScanner scanner)
{
scanner.StatusUpdated -= this.Scanner_StatusUpdated;
scanner.Dispose();
this.btScannerList.Remove(scanner);
scanner = null;
}
private void DisposeClaimedScanner(ClaimedBarcodeScanner claimedScanner)
{
// Detach the event handlers
claimedScanner.DataReceived -= this.ClaimedScanner_DataReceived;
claimedScanner.ReleaseDeviceRequested -= this.ClaimedScanner_ReleaseDeviceRequested;
// Release the Barcode Scanner and set to null
claimedScanner.Dispose();
this.ClaimedScannerList.Remove(claimedScanner);
claimedScanner = null;
}