我正在尝试复制这个内容丰富的教程,以使用 Xamarin Forms 行为对 Xamarin Forms 应用程序进行验证。本教程基于单个用户模型场景,而我的案例基于项目列表。我相信我的验证逻辑工作正常,但是,视图并没有改变以指示验证错误:本教程旨在为未成功验证的字段添加红色边框和内联验证错误消息。
在本教程中,验证是在构造函数中声明的命令中完成的,并且错误消息只是在模型的属性中设置。据我了解,这会更新 XAML 视图,因为视图中实现了数据绑定。就我而言,我正在尝试同样的事情,在保存命令中进行验证,并更新列表中的值。我还可以看到在列表中编辑了实际的“错误”对象,但视图中的 ExtendedEntry 没有按预期更新为红色边框和错误消息。我还尝试清除 ObservableCollection 并通过一次添加一项来重新构建它。我的问题是,为什么我的解决方案不适用于项目列表?在这种情况下逻辑不成立吗?
在下面添加一些片段以供参考:
本教程用于扩展 Entry 组件并创建一个 ExtendedEntry 组件,该组件接受更多属性,例如边框和内联验证消息。出于这个原因,每个平台都实现了自定义渲染器。还创建了一个入口行为来处理表单的行为变化。我不包括这些,因为我假设从链接复制和粘贴它们不应该破坏代码。
该模型包括2个验证字段,1个定义是否出现红色边框,另一个定义验证消息。
public class MetaData: INotifyPropertyChanged
{
public string Name { get; set; }
public string Value { get; set; }
public string Type { get; set; }
public bool Mandatory { get; set; }
public bool IsNotValid { get; set; }
public string NotValidMessageError { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
}
ViewModel 构造函数,它还包含 OnValidationCommand。我不确定全局列表是否绑定到视图。所以我尝试一一更新 List 和 Observable 集合。
public ObservableCollection<MetaData> Items { get; set; }
public List<MetaData> MetadataList { get; set; }
public ICommand OnValidationCommand { get; set; }
public MetadataPreviewViewModel(List<MetaData> md)
{
MetadataList = md;
OnValidationCommand = new Command((obj) =>
{
Items.Clear();
bool errorValidation = false;
for (int i = 0; i < MetadataList.Count; i++)
{
var item = MetadataList[i];
var tempItem = Validate(item);
MetadataList[i] = tempItem;
Items.Add(tempItem);
}
});
Title = "Metadata";
Items = new ObservableCollection<MetaData>();
LoadItemsCommand = new Command(async () => await ExecuteLoadItemsCommand());
}
public MetaData Validate(MetaData item)
{
int intType = Convert.ToInt16(item.Type);
switch (intType)
{
case (int)DefaultValueType.Custom_Date:
// need to validate date
item.IsNotValid = false;
break;
default: {
if (item.Mandatory)
{
if (item.Value != null && item.Value != "")
item.IsNotValid = false;
else
{
item.IsNotValid = true;
item.NotValidMessageError = item.Name + " is required.";
}
}
break;
}
}
return item;
}
在 XAML 中,我使用各种 DataTemplates 和 DataTemplateSelector 在 XAML 中包含具有不同组件的不同布局。我只尝试在这个模板中实现验证。下面是 ResourceDictionary 中的 DataTemplate 声明和带有 ListView 声明的 ContentPage.Content 部分,还指定了一个模板选择器。请注意,模板选择器工作正常,并且针对不同场景显示了正确的模板。
<ResourceDictionary>
<DataTemplate x:Key="textTemplate">
<ViewCell>
<Grid Padding="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.4*" />
<ColumnDefinition Width="0.6*" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Text="{Binding Name}" HorizontalOptions="Start"/>
<local1:ExtendedEntry Grid.Column="1" ErrorText="{Binding NotValidMessageError, Mode=TwoWay}"
BorderErrorColor="Red"
Text="{Binding Value, Mode=TwoWay}"
HeightRequest="40"
IsBorderErrorVisible="{Binding IsNotValid, Mode=TwoWay}" InputTransparent="{Binding ROnly}">
<local1:ExtendedEntry.Behaviors>
<behavior:EmptyEntryValidationBehaviour />
</local1:ExtendedEntry.Behaviors>
</local1:ExtendedEntry>
</Grid>
</ViewCell>
</DataTemplate>
<local:MetaDataTemplateSelector x:Key="metaDataTemplateSelector"
TextTemplate="{StaticResource textTemplate}"
CheckboxTemplate="{StaticResource checkboxTemplate}"
DatePickerTemplate="{StaticResource datepickerTemplate}"
NumericTemplate="{StaticResource numericTemplate}"/>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout>
<ListView x:Name="MetadataListView"
ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource metaDataTemplateSelector}"
VerticalOptions="FillAndExpand"
HasUnevenRows="true"
RefreshCommand="{Binding LoadItemsCommand}"
IsPullToRefreshEnabled="true"
IsRefreshing="{Binding IsBusy, Mode=TwoWay}"
CachingStrategy="RecycleElement">
</ListView>
<Button Text="Save" Command="{Binding OnValidationCommand}"></Button>
</StackLayout>
</ContentPage.Content>