OnPropertyChanged не обновляет пользовательский интерфейс для xzing barcode scanner для xamarin

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