using Microsoft.AspNetCore.Components; using Microsoft.JSInterop; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using EgwCoreLib.Utils; using ZXingBlazor.Components; namespace EgwCoreLib.Razor { public partial class BarcodeReader : IAsyncDisposable { #region Public Properties /// /// Close scan code callback method /// [Parameter] public EventCallback Close { get; set; } /// /// Close button title /// [Parameter] public string CloseBtnTitle { get; set; } = "Close"; /// /// Decode All Formats, performance is poor, you can set options.formats to customize /// specify the encoding formats. The default is false /// [Parameter] public bool DecodeAllFormats { get; set; } /// /// Decode Once or Decode Continuously, default is Once /// [Parameter] public bool Decodeonce { get; set; } = true; /// /// Device ID /// [Parameter] public string? DeviceID { get; set; } /// /// public ElementReference Element { get; set; } /// /// Error callback method /// [Parameter] public Func? OnError { get; set; } /// /// ZXingOptions /// [Parameter] public ZXingOptions? Options { get; set; } /// /// Decode only Pdf417 format /// [Parameter] public bool Pdf417Only { get; set; } /// /// Reset button title /// [Parameter] public string ResetBtnTitle { get; set; } = "Reset"; /// /// Save the last used device ID to be called automatically next time /// [Parameter] public bool SaveDeviceID { get; set; } = true; /// /// Scan button title /// [Parameter] public string ScanBtnTitle { get; set; } = "Scan"; /// /// Scan result callback method /// [Parameter] public EventCallback ScanResult { get; set; } /// /// Select device button title /// [Parameter] public string SelectDeviceBtnTitle { get; set; } = "Select Device"; /// /// Use builtin Div /// [Parameter] public bool UseBuiltinDiv { get; set; } = true; #endregion Public Properties #region Public Methods [JSInvokable] public async Task CloseScan() => await Close.InvokeAsync(); async ValueTask IAsyncDisposable.DisposeAsync() { await module!.InvokeVoidAsync("destroy", Element.Id); Instance?.Dispose(); if (module is not null) { await module.DisposeAsync(); } } [JSInvokable] public async Task GetError(string err) { if (OnError != null) await OnError.Invoke(err); } [JSInvokable] public async Task GetResult(string val) => await ScanResult.InvokeAsync(val); public async Task Reload() { await module!.InvokeVoidAsync("reload", Element.Id); } /// /// 选择摄像头回调方法 /// /// /// [JSInvokable] public async Task SelectDeviceID(string deviceID, string deviceName) { try { if (SaveDeviceID) { await Storage.SetValue("CamsDeviceID", deviceID); await Storage.SetValue("CamsDeviceName", deviceName); } } catch { } } public async Task Start() { await module!.InvokeVoidAsync("start", Element.Id); } public async Task Stop() { await module!.InvokeVoidAsync("stop", Element.Id); } #endregion Public Methods #region Protected Methods // To prevent making JavaScript interop calls during prerendering protected override async Task OnAfterRenderAsync(bool firstRender) { try { if (!firstRender) return; Storage = new StorageService(JS); module = await JS.InvokeAsync("import", "./_content/EgwCoreLib.Razor/BarcodeReader.razor.js"); #if false module = await JS.InvokeAsync("import", "./_content/EgwCoreLib.Razor/BarcodeReader.razor.js" + "?v=" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version); #endif Instance = DotNetObjectReference.Create(this); if (Options == null) { Options = new ZXingOptions() { Pdf417 = Pdf417Only, Decodeonce = Decodeonce, DecodeAllFormats = DecodeAllFormats, //TRY_HARDER = true }; } try { if (SaveDeviceID) { DeviceID = await Storage.GetValue("CamsDeviceID", DeviceID); } } catch (Exception) { } await module.InvokeVoidAsync("init", Instance, Element, Element.Id, Options, DeviceID); } catch (Exception e) { if (OnError != null) await OnError.Invoke(e.Message); } } #endregion Protected Methods #region Private Fields private IJSObjectReference? module; #endregion Private Fields #region Private Properties private DotNetObjectReference? Instance { get; set; } [Inject] [NotNull] private IJSRuntime? JS { get; set; } [NotNull] private StorageService? Storage { get; set; } #endregion Private Properties #region Private Classes private class StorageService { #region Public Constructors public StorageService(IJSRuntime jsRuntime) { JSRuntime = jsRuntime; } #endregion Public Constructors #region Public Methods public static T? GetValueI(string value) { TypeConverter converter = TypeDescriptor.GetConverter(typeof(T)); if (converter != null) { return (T?)converter.ConvertFrom(value); } return default; //return (T)Convert.ChangeType(value, typeof(T)); } public async Task GetValue(string key, TValue? def) { try { var cValue = await JSRuntime.InvokeAsync("eval", $"localStorage.getItem('{key}');"); return cValue ?? def; } catch { var cValue = await JSRuntime.InvokeAsync("eval", $"localStorage.getItem('{key}');"); if (cValue == null) return def; var newValue = GetValueI(cValue); return newValue ?? def; } } public async Task RemoveValue(string key) { await JSRuntime.InvokeVoidAsync("eval", $"localStorage.removeItem('{key}')"); } public async Task SetValue(string key, TValue value) { await JSRuntime.InvokeVoidAsync("eval", $"localStorage.setItem('{key}', '{value}')"); } #endregion Public Methods #region Private Fields private readonly IJSRuntime JSRuntime; #endregion Private Fields } #endregion Private Classes } }