1

我正在尝试复制这个内容丰富的教程,以使用 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>
4

0 回答 0