#c# #xamarin #mvvm #data-binding #barcode-scanner
#c# #xamarin #mvvm #привязка данных #сканер штрих-кода
Вопрос:
Я использую mvvm, хотя мое приложение, привязка данных и изменения свойств работают везде в приложении, но по какой-то причине, на мой взгляд, с помощью XZing Barcode Scanner, мое представление не обновляется после сканирования элемента.
Я привык работать с XAML ViewModel и Codebehind, но способ настройки сканера штрих-кодов — это только ViewModel и Codebehind / alone class. Так что, возможно, мне не хватает чего-то простого, к чему я просто не привык.
Я опубликовал ниже некоторый код, который является примером только одного из свойств, которое не обновляется, имя партнера для productsLable.Text. Он привязывается при первой загрузке страницы, и фиктивное имя партнера отображается правильно, но после сканирования нового элемента я обновляю ScannedPart в моей ViewModel, но «get» никогда не вызывается после того, как я установил и вызвал OnPropertyChanged();
Это хорошо работает в других частях моего приложения, но, возможно, я упускаю здесь что-то глупое, как я уже сказал, мне удобнее работать с привязками в XAML. Вы видите что-нибудь, что я могу делать неправильно или пропускать?
Заранее спасибо.
public class TimsCustomScanPage : ContentPage
{
ZXingScannerView zxing;
TimsCustomOverlay overlay;
RequestPartsViewModel viewModel;
public TimsCustomScanPage(RequestPartsViewModel viewModel) : base()
{
//Attaching ViewModel
this.viewModel = viewModel;
this.BindingContext = viewModel;
//Scanner found barcode
zxing.OnScanResult = (result) =>
{
// Stop analysis until we navigate away so we don't keep reading barcodes
zxing.IsAnalyzing = false;
//Setting new scanned part
viewModel.ScannedPart = viewModel.Parts.FirstOrDefault();
};
--Some more code--
var productsLabel = new Label()
{
//Text = "Find New Part",
TextColor = Color.Black,
WidthRequest = 150,
HorizontalOptions = LayoutOptions.Start,
VerticalTextAlignment = TextAlignment.Center,
Padding = new Thickness(0, 0, 0, 0),
};
//Binding text property
productsLabel.SetBinding(Label.TextProperty, "PartName");
productsLabel.BindingContext = viewModel.ScannedPart;
}
ViewModel
public class RequestPartsViewModel : BaseViewModel
{
public ObservableCollection<TimsCategory> Categories { get; set; }
public ObservableCollection<TimsCategory> FavoriteCategories { get; set; }
public ObservableCollection<TimsPart> Parts { get; set; }
public TimsCategory CurrentSelection { get; set; }
public Command LoadItemsCommand { get; set; }
TimsPart scannedPart;
string partName;
int totalRequestedParts;
public RequestPartsViewModel()
{
Title = "Request Parts";
Categories = new ObservableCollection<TimsCategory>(db.Table<TimsCategory>().ToList());
Parts = new ObservableCollection<TimsPart>(db.Table<TimsPart>().ToList());
TotalRequestedParts = 0;
ScannedPart = new TimsPart();
ScannedPart.PartName = "Scan New Part";
ScannedPart.AvailableQuantity = 0;
//Attach parts to categories
foreach (var item in Categories)
{
int newId = item.CategoryId;
var partsForCategories = Parts.Where(p => p.CategoryId == newId);
var partsForCategoriesCollection = new ObservableCollection<TimsPart>(partsForCategories);
item.Parts = partsForCategoriesCollection;
}
FavoriteCategories = new ObservableCollection<TimsCategory>(Categories.Take(6).ToList());
LoadItemsCommand = new Command(async () => await ExecuteLoadItemsCommand());
}
public TimsPart ScannedPart
{
get
{
return scannedPart;
}
set
{
if (scannedPart != value)
{
scannedPart = value;
OnPropertyChanged("PartName");
OnPropertyChanged("RequestedQuantity");
OnPropertyChanged("AvailableQuantity");
OnPropertyChanged("ScannedPart");
}
}
}
Базовая модель представления
public class BaseViewModel : INotifyPropertyChanged
{
public SQLiteConnection db = TimsData.database;
bool isBusy = false;
public bool IsBusy
{
get { return isBusy; }
set { SetProperty(ref isBusy, value); }
}
string title = string.Empty;
public string Title
{
get { return title; }
set { SetProperty(ref title, value); }
}
protected bool SetProperty<T>(ref T backingStore, T value,
[CallerMemberName]string propertyName = "",
Action onChanged = null)
{
if (EqualityComparer<T>.Default.Equals(backingStore, value))
return false;
backingStore = value;
onChanged?.Invoke();
OnPropertyChanged(propertyName);
return true;
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
Ответ №1:
Я думаю, проблема в том, что вы привязываетесь непосредственно к свойству, но затем меняете базовый объект, а не только свойство. Попробуйте это вместо
productsLabel.SetBinding(Label.TextProperty, "ScannedPart.PartName");
// you already have a BindingContext set for your page that the Label will inherit
// productsLabel.BindingContext = viewModel.ScannedPart;