Привязки данных не видят свойства viewmodel - PullRequest
0 голосов
/ 19 января 2020

Проблема :

Я пытаюсь создать то, что кажется простой установкой представления MVVM. Тем не менее, независимо от того, что я изменяю, я не могу подключить соединение PropertyChanged к .xaml и наоборот.

Вот представление:

VpicInformationPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:viewModels="clr-namespace:ScanditBarcodeScanner.ViewModels"
             x:Class="ScanditBarcodeScanner.Pages.VehicleOperationPages.VpicInformationPage">
    <!--<ContentPage.BindingContext>
        <viewModels:VpicInformationPageViewModel />
    </ContentPage.BindingContext>-->
    <StackLayout VerticalOptions="CenterAndExpand" Padding="5">
        <StackLayout.BindingContext>
            <viewModels:VpicInformationPageViewModel />
        </StackLayout.BindingContext>
        <Entry x:Name="VinEntry" Placeholder="VIN (Manual Entry)" />
        <Label Text="{Binding VinType.Make}" />
        <Label Text="{Binding VinType.Model}" />
        <Label Text="{Binding VinType.ModelYear}" />
        <Label Text="{Binding VinType.BodyClass}" />
        <Label Text="{Binding VinType.ErrorCode}" />
        <Button Text="Scan/Check VIN" Clicked="ScanOrCheckVin_Clicked"/>
    </StackLayout>
</ContentPage>

Модель:

VpicInformationPage.xaml.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using Scandit.BarcodePicker.Unified;
using Scandit.BarcodePicker.Unified.Abstractions;
using ScanditBarcodeScanner.ViewModels;
using ScanditBarcodeScanner.ViewModels.Base;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace ScanditBarcodeScanner.Pages.VehicleOperationPages
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class VpicInformationPage : ContentPage, INotifyPropertyChanged
    {
        IBarcodePicker _picker;

        VpicInformationPageViewModel ViewModel;
        public VpicInformationPage()
        {
            InitializeComponent ();

            ViewModel = BindingContext as VpicInformationPageViewModel;

            ViewModel.VinType = VehicleApi.EmptyVinType;

            _picker = ScanditService.BarcodePicker;

            SetVinSettings();

            _picker.DidScan += OnDidScan;

            VinEntry.Text = "";
        }
    //...
    }
}

Модель представления:

VpicInformationPageViewModel.cs

using ScanditBarcodeScanner.ViewModels.Base;
using System.ComponentModel;

namespace ScanditBarcodeScanner.ViewModels
{
    public class VpicInformationPageViewModel : ViewModelBase
    {
        #region VinType
        private VehicleApi.VinType _vinType;

        public VehicleApi.VinType VinType
        {
            get { return _vinType; }
            set
            {
                SetValue(ref _vinType, value, "VinType");
                Make = _vinType.Make;
                Model = _vinType.Model;
                ModelYear = _vinType.ModelYear;
                BodyClass = _vinType.BodyClass;
                ErrorCode = _vinType.ErrorCode;
            }
        }
        #endregion VinType

        #region VinType.Make
        private string _make;
        public string Make
        {
            get { return _vinType.Make; }
            private set
            {
                SetValue(ref _make, value);
            }
        }
        #endregion VinType.Make

        #region VinType.Model
        private string _model;

        public string Model
        {
            get { return _vinType.Model; }
            private set
            {
                SetValue(ref _model, value);
            }
        }
        #endregion VinType.Model

        #region VinType.ModelYear
        private string _modelYear;

        public string ModelYear
        {
            get { return _vinType.ModelYear; }
            private set
            {
                SetValue(ref _modelYear, value);
            }
        }
        #endregion VinType.ModelYear

        #region VinType.BodyClass
        private string _bodyClass;

        public string BodyClass
        {
            get { return _vinType.BodyClass; }
            private set
            {
                SetValue(ref _bodyClass, value);
            }
        }
        #endregion VinType.BodyClass

        #region VinType.ErrorCode
        private string _errorCode;

        public string ErrorCode
        {
            get { return _vinType.ErrorCode; }
            private set
            {
                SetValue(ref _errorCode, value);
            }
        }
        #endregion VinType.ErrorCode

        public VpicInformationPageViewModel()
        {
            _vinType = new VehicleApi.VinType();
        }
    }
}

ViewModelBase:

ViewModelBase.cs

using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace ScanditBarcodeScanner.ViewModels.Base
{
    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged([CallerMemberName] string PropertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
        }

        protected bool SetValue<T>(ref T BackingField, T Value, [CallerMemberName] string PropertyName = null)
        {
            if(EqualityComparer<T>.Default.Equals(BackingField, Value))
            {
                return false;
            }
            BackingField = Value;
            OnPropertyChanged(PropertyName);
            return true;
        }
    }

Я понял, что я не сделал не включает VehicleApi класс. Вот важная часть этого класса:

VehicleApi.cs

namespace ScanditBarcodeScanner
{
    public static class VehicleApi
    {
        public static VinType EmptyVinType { get; } = new VinType
        {
            Make = "Make",
            Model = "Model",
            ModelYear = "Model Year",
            BodyClass = "Body Class",
            ErrorCode = "Status/Error Code"
        };

        public class VinType
        {
            public string Make { get; set; }
            public string Model { get; set; }
            public string ModelYear { get; set; }
            public string BodyClass { get; set; }
            public string ErrorCode { get; set; }
        }
}

Насколько я понимаю, я правильно реализовал эти файлы и правильно связал их вместе. Однако каждый раз, когда я запускаю приложение, я получаю:

[0:] Binding: 'VinType' property not found on 'ScanditBarcodeScanner.ViewModels.VpicInformationPageViewModel', target property: 'Xamarin.Forms.Label.Text'

Я привязал View к ViewModel и реализовал INotifyPropertyChanged.

У меня есть перепробовал много решений, таких как изменение места установки контекста привязки (либо в ContentPage, либо в StackLayout, либо даже в обоих), пробовал разные методы уведомления представления об изменении свойств и привязывал метки к базовым элементам VinType, и позволяя VinType изменять и поднимать PropertyChanged для них. Я даже пробовал PropertyChanged.Fody, но, похоже, проблема не в коде уведомления, а в том, как я связал View и ViewModel вместе или, возможно, в том, как определены свойства.

Вопрос:

Какая часть подключения переплета отсутствует / неверна? В документации говорится, что я должен иметь возможность получить доступ к VinType и его членам с помощью предоставленного мною кода.

Ссылка на образец

Проблема с проектом выше, это то, что, хотя оно и не выдает ту же ошибку, о которой я говорю, оно все равно не меняет поля, когда должно.

1 Ответ

0 голосов
/ 31 января 2020

Итак, решение этой проблемы было на самом деле довольно простым.

Мне просто нужно было изменить определения меток с <Label Text="{Binding PropertyName.Member}" /> на <Label Text="{Binding PropertyName.Member, StringFormat='{}{0}'}">

Причина, по которой это необходимо {} в строке формата вызвано ошибкой, возникающей при использовании одинарных кавычек '' вместо двойных кавычек "" при определении StringFormat.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...