繁体   English   中英

有没有更好的方法来使用条形码扫描仪?

[英]Is there a better way to use barcode scanner?

我目前正在使用UWP App中的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中使用返回的值?

在使用MVVM时,WPF开发人员存在类似的模式,您需要获取/更新视图模型(VM)正在公开的模型。 也许他们在数据库中。 可以将“服务”传递到VM,而不是用丑陋的DB代码污染您的好VM。 现在,“serivce”并不一定意味着SOA /微服务,也许它只是另一个项目中的另一个类。 关键是你把所有的条形码放在那里,当收到某些东西时,它可能会触发你的VM监听的事件,或者它只是将它排队等待你的VM通过服务接口请求。

我已经在服务类中拥有所有条形码代码,并且存在问题,因为我不希望服务类更新我当前的模型。 我遇到的主要问题是我不知道如何让我的VM监听DataReceived事件

好吧,从我可以看到你的服务没有与UWP MVVM分离。 对于此事件,您是否考虑过仅为VM客户端公开二级事件? 我觉得这对我很有用。

就像VM中的事件监听数据接收事件一样?

是的,但它不一定只是一个物理event类型的概念。 C#事件意味着可能不止一个用户对条形码应用程序没有任何意义。 应该只有一个前景阅读器。

在这里,我将使用Action<string>将条形码从BarcodeScanner传递给客户端,在本例中为VM。 通过使用Action并将条形码处理移动到客户端,我们保持BarcodeScanner完全不知道MVVM。 Windows.ApplicationModel.Core.CoreApplication.MainView使得BarcodeScanner令人难以置信地与它不应该关心的东西相结合。

首先,我们想要解耦所有内容,所以首先是一个代表条形码扫描器重要位的接口:

public interface IBarcodeScanner
{
    Task<bool> ClaimScannerAsync();
    void Subscribe(Action<string> callback);
    void Unsubscribe();
}

有了这个定义,我们将它传递到你的VM,如下所示:

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;
    }

接下来我们添加一些命令处理程序。 想象一下,我们有一个按钮,点击后,开始条形码订阅。 将以下内容添加到VM:

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);

    }
}

那问题是什么?

总而言之,你有点陷入一种循环依赖问题,其中VM依赖于BarcodeScannerBarcodeScanner依赖于表示API - 这是它不应该知道的。 即使你在BarcodeScanner中对于BarcodeScanner有很好的抽象尝试(遗憾的是不是Poste的情况),扫描层IScannable假设使用它的用户类型。 这只是为了垂直

使用这种新方法,如果需要,您可以将其用于其他类型的应用程序,包括UWP控制台应用程序。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM