我目前正在 UWP 应用程序中使用 BarcodeScanner
。
为了实现它,我遵循了 Microsoft 文档上的一些教程。
它工作正常,但不像我想要的那样工作。
条码扫描器只能通过DataReceived
事件获取该值。
因此,当我想从 BarcodeScanner
返回值时,这是不可能的。
我在这里注册扫描仪:
private static async Task<bool> ClaimScanner()
{
bool res = false;
string selector = BarcodeScanner.GetDeviceSelector();
DeviceInformationCollection deviceCollection = await
DeviceInformation.FindAllAsync(selector);
if (_scanner == null)
_scanner = await BarcodeScanner.FromIdAsync(deviceCollection[0].Id);
if (_scanner != null)
{
if (_claimedBarcodeScanner == null)
_claimedBarcodeScanner = await _scanner.ClaimScannerAsync();
if (_claimedBarcodeScanner != null)
{
_claimedBarcodeScanner.DataReceived += ClaimedBarcodeScanner_DataReceivedAsync;
[...]
}
}
}
一旦我收到数据,它就会触发该事件:
private static async void ClaimedBarcodeScanner_DataReceivedAsync(ClaimedBarcodeScanner sender, BarcodeScannerDataReceivedEventArgs args)
{
await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
if (CurrentDataContext != null && CurrentDataContext is IScannable)
{
IScannable obj = (IScannable)CurrentDataContext;
obj.NumSerie = CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf8, args.Report.ScanDataLabel);
}
else if (CurrentDataContext != null && CurrentDataContext is Poste)
{
Poste p = (Poste)CurrentDataContext;
string code = CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf8, args.Report.ScanDataLabel);
p.CodePoste = code.Substring(0, 6);
}
});
}
正如您所看到的,我被迫在该方法中执行所有操作(更新其他类的实例等)。
目前我正在像 ViewModel 中那样调用 BarcodeScanner :
public void ScanPosteCodeAsync()
{
BarcodeScannerUtil.ScanBarcodeUtil(CurrentPoste);
}
但是我无法控制我的 CurrentPoste
实例,我会做的更像是:
public void ScanPosteCodeAsync()
{
string returnedCode = BarcodeScannerUtil.ScanBarcodeUtil()
this.CurrentPoste.Code = returnedCode;
}
有没有办法返回扫描仪的值,以便在我的 ViewModel 中使用返回的值?
最佳答案
WPF 开发人员在使用 MVVM 时也存在类似的模式,并且您需要获取/更新 View 模型 (VM) 公开的模型。也许它们在数据库中。可以将“服务”传递到虚拟机中,而不是用丑陋的数据库代码污染你的漂亮虚拟机。现在,“服务”并不一定意味着 SOA/微服务,也许它只是不同项目中的另一个类。关键是您将所有条形码内容放在那里,当收到某些内容时,它可能会触发您的虚拟机监听的事件,或者可能只是将其排队等待您的虚拟机通过服务接口(interface)请求。
I already have all the barcode code in a service class, and there's the problem because I don't want the service class to update my current model. The major issue I have is that I don't know how to do to make my VM listen to the DataReceived event
嗯,据我所知,您的服务并未与 UWP MVVM 解耦。对于该事件,您是否考虑过纯粹为 VM 客户端公开次要事件?我发现这对我来说很有效。
Like an event in the VM listening to the data received event ?
是的,但不一定是聆听实体 event
仅输入概念。 C# 事件意味着可以有多个订阅者,这对于条形码应用程序来说实际上没有意义。应该只有一名前台读者。
这里我将使用Action<string>
传递来自BarcodeScanner
的条形码到客户端,在本例中是虚拟机。通过使用 Action
并将条形码处理移至客户端,我们保留 BarcodeScanner
完全不知道MVVM。 Windows.ApplicationModel.Core.CoreApplication.MainView
正在制作 BarcodeScanner
与它不应该关心的东西难以置信地耦合。
首先,我们希望将所有内容解耦,因此首先是一个代表条形码扫描仪重要部分的接口(interface):
public interface IBarcodeScanner
{
Task<bool> ClaimScannerAsync();
void Subscribe(Action<string> callback);
void Unsubscribe();
}
定义后,我们将把它传递到您的虚拟机中,如下所示:
public class MyViewModel
{
private readonly IBarcodeScanner _scanner;
/// <summary>
/// Initializes a new instance of the <see cref="MyViewModel"/> class.
/// </summary>
/// <param name="scanner">The scanner, dependency-injected</param>
public MyViewModel(IBarcodeScanner scanner)
{
// all business logic for scanners, just like DB, should be in "service"
// and not in the VM
_scanner = scanner;
}
接下来我们添加一些命令处理程序。想象一下,我们有一个按钮,单击该按钮即可启动条形码订阅。将以下内容添加到虚拟机:
public async void OnWidgetExecuted()
{
await _scanner.ClaimScannerAsync();
_scanner.Subscribe(OnReceivedBarcode);
}
// Barcode scanner will call this method when a barcode is received
private void OnReceivedBarcode(string barcode)
{
// update VM accordingly
}
最后,BarcodeScanner
的新外观:
public class BarcodeScanner : IBarcodeScanner
{
/// <summary>
/// The callback, it only makes sense for one client at a time
/// </summary>
private static Action<string> _callback; // <--- NEW
public async Task<bool> ClaimScannerAsync()
{
// as per OP's post, not reproduced here
}
public void Subscribe(Action<string> callback) // <--- NEW
{
// it makes sense to have only one foreground barcode reader client at a time
_callback = callback;
}
public void Unsubscribe() // <--- NEW
{
_callback = null;
}
private void ClaimedBarcodeScanner_DataReceivedAsync(ClaimedBarcodeScanner sender, BarcodeScannerDataReceivedEventArgs args)
{
if (_callback == null) // don't bother with ConvertBinaryToString if we don't need to
return;
// all we need do here is convert to a string and pass it to the client
var barcode = CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf8,
args.Report.ScanDataLabel);
_callback(barcode);
}
}
那么问题出在哪里?
总而言之,您陷入了某种循环依赖问题,即虚拟机依赖于 BarcodeScanner
和 BarcodeScanner
依赖于表示 API - 这是它不需要了解的东西。即使您在 BarcodeScanner
中对抽象做了很好的尝试。关于IScannable
(遗憾的是 Poste
不是这种情况),扫描层正在假设使用它的用户类型。它只是垂直。
通过这种新方法,如果需要,您可以将其用于其他类型的应用,包括 UWP 控制台应用。
关于c# - 有没有更好的方法来使用条码扫描仪?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56325605/