проверка формы net maui

Все еще изучаю. Я пытаюсь выполнить проверку модели с помощью CommunityToolkit.Mvvm, и я застрял в стилях (минимум там).

Вот что я пробовал:

Модель:

      public abstract partial class BaseModel : ObservableObject, IDataErrorInfo
{
    private Dictionary<string, string> validationErrors = new Dictionary<string, string>();
    private bool isValid = false;

    protected Dictionary<string, string> ValidationErrors
    {
        get => validationErrors;
        private set => SetProperty(ref validationErrors, value);
    }

    protected bool IsValid
    {
        get => isValid;
        private set => SetProperty(ref isValid, value);
    }

    [RelayCommand]
    protected void Validate()
    {
        var context = new ValidationContext(this);
        var errors = new List<ValidationResult>();

        isValid = Validator.TryValidateObject(this, context, errors, true);
        foreach (var error in errors)
        {
            var columnName = error.MemberNames.First();

            if(!validationErrors.ContainsKey(columnName))
                validationErrors.Add(columnName, error.ErrorMessage);
        }
    }


    // check for general model error
    public string Error { get; private set; } = null;

    // check for property errors
    public string this[string columnName]
    {
        get
        {
            Validate();
            return validationErrors[columnName];
        }
    }
}

public class PlayerModel : BaseModel
{
    public int Id { get; set; }

    [Required]
    [StringLength(255)]
    public string Name { get; set; }

    [StringLength(4096)]
    public string LocalImageLink { get; set; }

    [Required]
    [StringLength(4096)]
    public string WebImageLink { get; set; }

    [Required]
    [StringLength(255)]
    public string Club { get; set; }

    [Required]
    [StringLength(32)]
    public string Birthday { get; set; }

    [Required]
    [StringLength(255)]
    public string BirthPlace { get; set; }

    [Required]
    [Range(0, 100)]
    public int Weight { get; set; }

    [Required]
    [Range(0, 2.5)]
    public double Height { get; set; }

    [Required]
    public string Description { get; set; }

    public string PositionName { get; set; }

    [Required]
    [Range(1, 7)]
    public int PositionId { get; set; }

    public PlayerModel()
    {
    }

    public PlayerModel(int id, string name, string localImageLink, string webImageLink, string club, string birthday, string birthPlace, int weight, double height, string description, string positionName, int positionId)
    {
        Id = id;
        Name = name;
        LocalImageLink = localImageLink;
        WebImageLink = webImageLink;
        Club = club;
        Birthday = birthday;
        BirthPlace = birthPlace;
        Weight = weight;
        Height = height;
        Description = description;
        PositionName = positionName;
        PositionId = positionId;
    }

    public PlayerModel(int id, string name, string localImageLink, string webImageLink, string club, string birthday, string birthPlace, int weight, double height, string description, PositionModel position)
    {
        Id = id;
        Name = name;
        LocalImageLink = localImageLink;
        WebImageLink = webImageLink;
        Club = club;
        Birthday = birthday;
        BirthPlace = birthPlace;
        Weight = weight;
        Height = height;
        Description = description;
        PositionName = position.Name;
        PositionId = position.Id;
    }

    public PlayerModel(PlayerEntity player)
    {
        Id = player.Id;
        Name = player.Name;
        LocalImageLink = player.LocalImageLink;
        WebImageLink = player.WebImageLink;
        Club = player.Club;
        Birthday = player.Birthday;
        BirthPlace = player.BirthPlace;
        Weight = player.Weight;
        Height = player.Height;
        Description = player.Description;
        PositionName = player.Position.Name;
        PositionId = player.Position.Id;
    }

    public PlayerEntity ToEntity()
    {
        return new PlayerEntity
        {
            Id = Id,
            Name = Name,
            LocalImageLink = LocalImageLink,
            WebImageLink = WebImageLink,
            Club = Club,
            Birthday = Birthday,
            BirthPlace = BirthPlace,
            Weight = Weight,
            Height = Height,
            Description = Description,
            Position = new PositionEntity
            { 
                Id = PositionId,
                Name = PositionName
            }
        };
    }

    public void ToEntity(PlayerEntity player)
    {
        player.Id = Id;
        player.Name = Name;
        player.LocalImageLink = LocalImageLink;
        player.WebImageLink = WebImageLink;
        player.Club = Club;
        player.Birthday = Birthday;
        player.BirthPlace = BirthPlace;
        player.Weight = Weight;
        player.Height = Height;
        player.Description = Description;

        player.Position.Id = PositionId;
        player.Position.Name = PositionName;
    }
}

Вид:

      <?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiUI.Pages.AddOrUpdatePlayer"
             xmlns:local="clr-namespace:Backend.Models;assembly=Backend.Models"
             xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit">

    <ContentPage.BindingContext>
        <local:PlayerModel />
    </ContentPage.BindingContext>

    <ContentPage.ToolbarItems>
        <ToolbarItem IconImageSource="save.svg" Clicked="OnSaveClick"/>
    </ContentPage.ToolbarItems>

    <ScrollView Margin="10">
        <VerticalStackLayout>
            <VerticalStackLayout>
                <Label Text="Name" />
                <Entry x:Name="name" Text="{Binding Name, Mode=TwoWay}"
                       ClearButtonVisibility="WhileEditing">
                    <Entry.Behaviors>
                        <toolkit:EventToCommandBehavior
                                EventName="TextChanged"
                                Command="{Binding Validate}" />
                    </Entry.Behaviors>
                </Entry>
            </VerticalStackLayout>
            <VerticalStackLayout Margin="0,10">
                <Label Text="Position" />
                <Picker x:Name="position" Title="Select..."
                        ItemDisplayBinding="{Binding Name}"
                        SelectedItem="{Binding PositionId, Mode=TwoWay}" />
            </VerticalStackLayout>
            <VerticalStackLayout Margin="0,10">
                <Label Text="Club" />
                <Entry x:Name="club" Text="{Binding Club, Mode=TwoWay}" 
                       ClearButtonVisibility="WhileEditing" />
            </VerticalStackLayout>
            <VerticalStackLayout Margin="0,10">
                <Label Text="Birthday" />
                <DatePicker  x:Name="birthday" Date="{Binding Birthday, Mode=TwoWay}" />
            </VerticalStackLayout>
            <VerticalStackLayout Margin="0,10">
                <Label Text="Birth place" />
                <Entry x:Name="birthplace" Text="{Binding BirthPlace, Mode=TwoWay}" 
                       ClearButtonVisibility="WhileEditing" />
            </VerticalStackLayout>
            <VerticalStackLayout Margin="0,10">
                <Label Text="Weight" />
                <Entry x:Name="weight" Text="{Binding Weight, Mode=TwoWay}"
                       ClearButtonVisibility="WhileEditing" Keyboard="Numeric"/>
            </VerticalStackLayout>
            <VerticalStackLayout Margin="0,10">
                <Label Text="Height" />
                <Entry x:Name="height" Text="{Binding Height, Mode=TwoWay}" 
                       ClearButtonVisibility="WhileEditing" Keyboard="Numeric"/>
            </VerticalStackLayout>
            <VerticalStackLayout Margin="0,10">
                <Label Text="Image link" />
                <Entry x:Name="webImageLink" Text="{Binding WebImageLink, Mode=TwoWay}"
                       ClearButtonVisibility="WhileEditing"/>
            </VerticalStackLayout>
            <VerticalStackLayout Margin="0,10">
                <Label Text="Description" />
                <Editor x:Name="description" Text="{Binding Description, Mode=TwoWay}"
                        AutoSize="TextChanges"/>
            </VerticalStackLayout>
        </VerticalStackLayout>
    </ScrollView>
</ContentPage>

Посмотреть код позади:

      [QueryProperty(nameof(Player), "player")]
public partial class AddOrUpdatePlayer : ContentPage
{
    private PlayerModel player;
    public PlayerModel Player
    {
        get => player;
        set
        {
            player = value;
            OnPropertyChanged();
        }
    }


    private readonly IPositionClient positionClient;
    private readonly IPlayerClient playerClient;

    private delegate Task Action();
    private Action asyncAction;

    public AddOrUpdatePlayer(IPositionClient positionClient, IPlayerClient playerClient)
    {
        InitializeComponent();
        SetUpControls();
        SetTitle();
        SetActionPointer();

        this.positionClient = positionClient;
        this.playerClient = playerClient;
    }

    protected async override void OnAppearing()
    {
        BindingContext = player;
        await SetUpPositionPicker();
    }

    private void SetUpControls()
    {
        birthday.MinimumDate = new DateTime(1900, 1, 1);
        birthday.MaximumDate = DateTime.Now.Date;
    }

    private async Task SetUpPositionPicker()
    {
        position.ItemsSource = await this.positionClient.GetAllAsync();
    }

    private void SetTitle()
    {
        Title = this.player is null ?
                "Add new player" :
                 $"Update {player.Name}";
    }

    private void SetActionPointer()
    {
        asyncAction = this.player is null ?
                      AddNewPlayer :
                      UpdatePlayer;
    }

    private async Task AddNewPlayer()
    {
        var player = BindingContext as PlayerModel;

        await playerClient.CreateAsync(player);

        await Shell.Current.GoToAsync(PageRoutes.HomePage, true);
    }

    private async Task UpdatePlayer()
    { }

    private async void OnSaveClick(object sender, EventArgs e)
    {
        await asyncAction();
    }
}

Глобальный стиль:

      <?xml version="1.0" encoding="UTF-8" ?>
<?xaml-comp compile="true" ?>
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:mct="http://schemas.microsoft.com/dotnet/2022/maui/toolkit">

    <Entry.Style>
        <OnPlatform x:TypeArguments="Style">
            <On Platform="iOS, Android" Value="{StaticResource EntryStyle}" />
            <On Platform="WinUI" Value="{StaticResource WinUIEntryStyle}" />
        </OnPlatform>
    </Entry.Style>
    <Entry.Behaviors>
        <mct:EventToCommandBehavior
        EventName="TextChanged"
        Command="{Binding Validate}" />
    </Entry.Behaviors>
    <Entry.Triggers>
        <DataTrigger
        TargetType="Entry"
        Binding="{Binding UserName.IsValid}"
        Value="False">
            <Setter Property="BackgroundColor" Value="{StaticResource ErrorColor}" />
        </DataTrigger>
    </Entry.Triggers>

</ResourceDictionary>

Мне нужно изменить свойство Entry.Triggers DataTrigger Binding, чтобы адаптироваться к моему решению, если это возможно. Моя другая проблема заключается в том, что при нажатии кнопки для сохранения BindingContext имеет значение null, данные не привязываются к модели в функции AddNewPlayer().

0 ответов

Другие вопросы по тегам