>source

현재 BarcodeScanner 를 사용하고 있습니다  UWP 앱에서. 이를 구현하기 위해 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에서 반환 된 값을 사용하기 위해 스캐너의 값을 반환하는 방법이 있습니까?

  • 답변 # 1

    MVVM을 사용할 때 WPF 개발자들에게도 비슷한 패턴이 있으며 뷰 모델 (VM)이 노출하는 모델을 가져 오거나 업데이트해야합니다. 아마도 그들은 데이터베이스에 있습니다. 추악한 DB 코드로 멋진 VM을 오염시키지 않고 "서비스"를 VM으로 전달할 수 있습니다. 이제 "비밀"이 SOA/마이크로 서비스를 의미하는 것은 아니며 다른 프로젝트의 다른 클래스 일 수도 있습니다. 요점은 모든 바코드 항목을 거기에 넣고 무언가를 받으면 VM이 청취하는 이벤트를 발생 시키거나 VM이 서비스 인터페이스를 통해 VM이 요청할 수 있도록 어딘가에 대기시키는 것입니다.

    와이즈 비즈

    자, 내가 볼 수있는 것에서 귀하의 서비스가 UWP MVVM과 분리되지 않았습니다. 이벤트의 경우 VM 클라이언트에 대한 보조 이벤트 노출 만 고려 했습니까? 나는 그것이 나에게 잘 맞는다는 것을 안다.

    와이즈 비즈

    그렇습니다. 그러나 물리적

    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

    에 대한 목록 엔딩 일 필요는 없습니다.  개념 만 입력하십시오. C # 이벤트는 바코드 앱에는 실제로 의미가없는 둘 이상의 구독자가 될 수 있음을 의미합니다. 포 그라운드 리더는 하나만 있어야합니다.

    여기서

    Like an event in the VM listening to the data received event ?

    를 사용하겠습니다   event 에서 바코드를 전달하려면  클라이언트 (이 경우 VM)에 Action<string> 를 사용하여  바코드 처리를 클라이언트로 옮기고 우리는 BarcodeScanner 를 유지합니다.  MVVM을 완전히 알지 못합니다. 와이즈 비즈   Action 를 만들고 있었다  신경 쓰지 말아야 할 것들에 엄청나게 결합되어 있습니다.

    먼저 우리는 모든 것을 분리하고 싶어서 바코드 스캐너의 중요한 부분을 나타내는 인터페이스입니다 :

    BarcodeScanner
    
    

    정의 된대로 다음과 같이 VM에 전달합니다.

    Windows.ApplicationModel.Core.CoreApplication.MainView
    
    

    다음으로 몇 가지 명령 처리기를 추가합니다. 클릭하면 바코드 구독을 시작하는 버튼이 있다고 상상해보십시오. VM에 다음을 추가하십시오.

    BarcodeScanner
    
    

    마침내, 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;
        }
    
    

    그래서 무슨 문제가 있었나요?

    요약하면 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  프리젠 테이션 API에 의존 할 필요가 없습니다. 당신이 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 의 경우는 아닙니다. )에서 스캐닝 계층은이를 사용하는 사용자 유형에 대해 가정합니다. 그것은 단지세로였습니다.

    이 새로운 접근 방식을 사용하면 필요한 경우 UWP 콘솔 앱을 포함한 다른 유형의 앱에 매우 유용하게 사용할 수 있습니다.

    BarcodeScanner

관련 자료

  • 이전 android - 푸시 알림 - 모바일에서 모바일로
  • 다음 java - Javaxxml 라이브러리로 XML 태그를 구문 분석하는 방법