Что ж, подобный шаблон существует для разработчиков WPF при использовании MVVM, и вам нужно получить / обновить модели, которые предоставляет ваша модель представления (VM).Возможно, они есть в базе данных.Вместо того, чтобы загрязнять вашу красивую виртуальную машину уродливым кодом БД, в нее может быть передана «служба».Теперь «serivce» не обязательно означает SOA / microservices, возможно, это просто еще один класс в другом проекте.Дело в том, что вы помещаете туда все свои штрих-коды, и когда что-то получено, возможно, оно запускает событие, которое слушает ваша виртуальная машина, или, возможно, оно просто ставит его в очередь где-то, готовое для вашей виртуальной машины, чтобы запросить через интерфейс службы.*
У меня уже есть весь штрих-код в классе обслуживания, и есть проблема, потому что я не хочу, чтобы класс обслуживания обновлял мою текущую модель.Основная проблема, с которой я столкнулся, заключается в том, что я не знаю, как сделать так, чтобы моя виртуальная машина прослушивала событие DataReceived
Что ж, из того, что я вижу, ваш сервис не отделен от UWP MVVM.Для события, вы рассматривали возможность выставления вторичного события исключительно для клиента виртуальной машины?Я считаю, что это хорошо работает для меня.
Как событие в виртуальной машине, слушающее событие получения данных?
Да, но это не обязательно должно бытьПрислушиваясь к физическому типу event
, просто концепция.События C # подразумевают, что может быть несколько подписчиков, что на самом деле не имеет смысла для приложений со штрих-кодом.Должен быть только один читатель переднего плана.
Здесь я буду использовать Action<string>
для передачи штрих-кода от BarcodeScanner
клиенту, в данном случае виртуальной машине.Используя Action
и перенося обработку штрих-кода на клиент, мы сохраняем BarcodeScanner
полностью не осведомленными о MVVM.Windows.ApplicationModel.Core.CoreApplication.MainView
делает 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;
}
Далее мы добавим некоторые обработчики команд.Представьте, что у нас есть кнопка, которая при нажатии запускает подписку со штрих-кодом.Добавьте к виртуальной машине следующее:
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, если вам нужно.