问题:
我正在尝试创建似乎是简单的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 = "";
}
//...
}
}
ViewModel:
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
及其成员。
上述项目的问题在于,尽管它没有给出我正在谈论的相同错误,但在预期的情况下仍不会更改字段。
答案 0 :(得分:0)
因此,解决此问题的方法实际上很简单。
我只需要更改标签定义
<Label Text="{Binding PropertyName.Member}" />
至<Label Text="{Binding PropertyName.Member, StringFormat='{}{0}'}">
在格式字符串中需要使用{}
的原因是由于在定义StringFormat时使用单引号''
而不是双引号""
时会出现错误。
编辑:尽管StringFormat问题很重要,但更大的问题是我使用的对象中的属性未定义get
或set
。
只要类型符合以下内容:
public class TypeName
{
public Type Property1 { get; set; }
public Type Property2 { get; set; }
}
然后,绑定引擎将能够查看和编辑成员属性。