Архитектура MAUI MVVM, создание системы входа в систему при использовании API

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

У меня есть три папки: Views, где я храню дизайн. Модели, где я храню классы. И ViewModels, которые получают данные. Это страница содержимого xaml, состоящая из страницы входа.

<?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 = "thebridgeproject.Views.login" 
             xmlns:ViewModels = "clr-namespace:thebridgeproject.ViewModels"
             Shell.NavBarIsVisible = "False"
             Title = "LoginPage" >
    <ContentPage.BindingContext>
        <ViewModels:LoginViewModel />
    </ContentPage.BindingContext>

    <VerticalStackLayout 
            Spacing = "25" 
            Padding = "30,0" 
            VerticalOptions = "Center">

            <Image Source = "loginicon.png" HeightRequest = "150" WidthRequest = "150" />

            <VerticalStackLayout Spacing = "5">
            <Label Text = "Welcome!" FontSize = "28" TextColor = "#3B7A5E" HorizontalTextAlignment = "Center" />
            <Label Text = "Login to your account" FontSize = "18" TextColor = "Gray" HorizontalTextAlignment = "Center" />
            </VerticalStackLayout>

            <StackLayout Orientation = "Horizontal">
                <Frame ZIndex = "1" HasShadow = "True" BorderColor = "White" HeightRequest = "56" WidthRequest = "56" CornerRadius = "28">
                    <Image Source = "user.png" HeightRequest = "20" WidthRequest = "20" />
                </Frame>
            <Frame HeightRequest = "45" Margin = "-20,0,0,0" Padding = "0" HasShadow = "True" BorderColor = "White"  HorizontalOptions = "FillAndExpand">
                <Entry Text = "{Binding Username}" Margin = "20,0,0,0" VerticalOptions = "Center" Placeholder = "Username"/>
            </Frame>
            </StackLayout>

            <StackLayout Orientation = "Horizontal">
                <Frame ZIndex = "1" HasShadow = "True" BorderColor = "White" HeightRequest = "56" WidthRequest = "56" CornerRadius = "28">
                    <Image Source = "lock.png" HeightRequest = "20" WidthRequest = "20" />
                </Frame>
            <Frame HeightRequest = "45" Margin = "-20,0,0,0" Padding = "0" HasShadow = "True" BorderColor = "White"  HorizontalOptions = "FillAndExpand">
                <Entry Text = "{Binding Password}" Margin = "20,0,0,0" VerticalOptions = "Center" Placeholder = "Password" IsPassword = "True" />
            </Frame>
            </StackLayout>

        <Button Text = "Sign in" WidthRequest = "100" CornerRadius = "20" HorizontalOptions = "Center" BackgroundColor = "#3B7A5E" Command = "{Binding LoginCommand}" />

            <StackLayout Orientation = "Horizontal" Spacing = "5" HorizontalOptions = "Center">
            <Label Text = "Dont have an account?" TextColor = "Gray" />
            <Label Text = "Sign up here" TextColor = "#50b3f2" />
            </StackLayout>
        </VerticalStackLayout>
    </ContentPage>

Затем у меня есть модель, которая содержит данные для запроса API.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace thebridgeproject.Models
{
    class users
    {

        public class Result
        {
            public int NumUtente { get; set; }
            public string Nome { get; set; }
            public string Password { get; set; }
            public string Morada { get; set; }
            public string Cidade { get; set; }
            public string DataNascimento { get; set; }
            public string NumTlf { get; set; }
        }

        public class Root
        {
            public bool success { get; set; }
            public string message { get; set; }
            public List<Result> result { get; set; }
        }

    }
}

После этого у нас есть LoginViewModel:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using thebridgeproject.Models;

namespace thebridgeproject.ViewModels
{
    public class LoginViewModel : INotifyPropertyChanged
    {
        private string _username;
        public string Username
        {
            get { return _username; }
            set
            {
                _username = value;
                OnPropertyChanged(nameof(Username));
            }
        }

        private string _password;
        public string Password
        {
            get { return _password; }
            set
            {
                _password = value;
                OnPropertyChanged(nameof(Password));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        private async Task Login()
        {
            using (var httpClient = new HttpClient())
            {

                httpClient.DefaultRequestHeaders.Add("Authorization", "RaV9N");
                var response = await httpClient.GetAsync("http:///bp/utentes");

                if (response.IsSuccessStatusCode)
                {
                    var content = await response.Content.ReadAsStringAsync();
                    var users = JsonConvert.DeserializeObject<users.Root>(content);

                    if (users.success)
                    {
                        var user = users.result.FirstOrDefault(x => x.Nome == Username);
                        if (user != null && VerifyPassword(user.Password, Password))
                        {
                            // Login successful
                            // ...
                        }
                        else
                        {
                            // Login failed
                            // ...
                        }
                    }
                    else
                    {
                        // API request failed
                        // ...
                    }
                }
                else
                {
                    // API request failed
                    // ...
                }
            }
        }

        private bool VerifyPassword(string hashedPassword, string enteredPassword)
        {
            // Use the BCrypt.Net library to verify the entered password
            return BCrypt.Net.BCrypt.Verify(enteredPassword, hashedPassword);
        }
    }
}

Не обращайте внимания на ссылку API! Но это в основном так, у меня больше нет кода. Вроде ничего не делает. Я думаю, что проблема может заключаться в отсутствии кода в файле дизайна. Я открыт для предложений, и я благодарен за любой продуктивный ответ!

"кажется, ничего не делает" - понятия не имею, что это значит. Пожалуйста, предоставьте более полезное описание, например "Когда я нажимаю кнопку X, я ожидаю, что метод Y будет выполнен, но это не так (или я получаю сообщение об ошибке, или исключение, и т. д.)"

Jason 13.02.2023 21:40

Используя точки останова и/или ведение журнала debug.writeline, точно определите, какая строка не делает то, что вы ожидаете.

ToolmakerSteve 13.02.2023 22:19

Привет Джейсон! Намерение состояло в том, чтобы выполнить код в LoginViewModel. Я уверен, что не понял функции ViewModel и хотел бы получить разъяснения. Он был предназначен для выполнения запроса к API, который предоставляет нам json-объект с логическим значением успеха, которое может быть истинным или ложным, сообщение, текст об успешном выполнении запроса и список всех пользователей. Мы используем этот список пользователей, чтобы проверить, совпадают ли они с именем пользователя и паролем, которые были вставлены во входные данные. Прошу прощения, если в моем вопросе недостаточно информации, обычно я никому не объясняю свой код.

Rafael Silva 13.02.2023 22:26

Раньше я добавлял точки останова в свой код, и он ничего не выполнял в модели представления.

Rafael Silva 13.02.2023 22:28

Ваша кнопка привязана к LoginCommand, но в вашей виртуальной машине нет ничего с именем LoginCommand. В вашей виртуальной машине не определено ни одного Commands

Jason 13.02.2023 22:46

О... Спасибо, Джейсон! В этом отношении, как я могу определить выполнение команды? Простое изменение входа в задачу на LoginCommand, кажется, не исправляет это, я что-то упустил в своей логике? Я что-то не так понял?

Rafael Silva 13.02.2023 23:05

Learn.microsoft.com/en-us/dotnet/maui/fundamentals/data-bind‌​ing/…

Jason 13.02.2023 23:16

Вместо того, чтобы писать код из 10 000 символов и наблюдать, что «он ничего не делает», вы можете начать с создания одного метода, состоящего из одной строки, и посмотреть, вызовется ли он вообще. «Но это в основном так, у меня больше нет кода», я видел страницы без XAML, но это первая, на которой есть только XAML.

H.A.H. 14.02.2023 08:36
Руководство для начинающих по веб-разработке на React.js
Руководство для начинающих по веб-разработке на React.js
Веб-разработка - это захватывающая и постоянно меняющаяся область, которая постоянно развивается благодаря новым технологиям и тенденциям. Одним из...
Разница между Angular и React
Разница между Angular и React
React и AngularJS - это два самых популярных фреймворка для веб-разработки. Оба фреймворка имеют свои уникальные особенности и преимущества, которые...
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Веб-скрейпинг, как мы все знаем, это дисциплина, которая развивается с течением времени. Появляются все более сложные средства борьбы с ботами, а...
Калькулятор CGPA 12 для семестра
Калькулятор CGPA 12 для семестра
Чтобы запустить этот код и рассчитать CGPA, необходимо сохранить код как HTML-файл, а затем открыть его в веб-браузере. Для этого выполните следующие...
ONLBest Online HTML CSS JAVASCRIPT Training In INDIA 2023
ONLBest Online HTML CSS JAVASCRIPT Training In INDIA 2023
О тренинге HTML JavaScript :HTML (язык гипертекстовой разметки) и CSS (каскадные таблицы стилей) - две основные технологии для создания веб-страниц....
Как собрать/развернуть часть вашего приложения Angular
Как собрать/развернуть часть вашего приложения Angular
Вам когда-нибудь требовалось собрать/развернуть только часть вашего приложения Angular или, возможно, скрыть некоторые маршруты в определенных средах?
0
8
74
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

View model реализует свойства и команды, к которым представление может привязываться к данным, и уведомляет view of о любых изменениях состояния посредством событий уведомления об изменении. view model также отвечает за координацию взаимодействия представления с любыми требуемыми классами модели. Обычно между моделью представления и классами модели существует отношение «один ко многим». Вы можете обратиться к Шаблон Model-View-ViewModel для более подробной информации.

Вы можете обратиться к моему примеру кода ниже, чтобы узнать, как использовать LoginCommand в вашем LoginCommand. Обратите внимание, что я поместил его в Label TapGestureRecognizer, однако его использование такое же, как и в Button.

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:ViewModel = "clr-namespace:MyApp.ViewModels"
             
             xmlns:local = "clr-namespace:MyApp"
             x:Class = "MyApp.Views.LoginPage"
             BackgroundColor = "#112B47"
             >
    <ContentPage.BindingContext>
        <ViewModel:LoginViewModel/>
    </ContentPage.BindingContext>

    <StackLayout  Padding = "15" VerticalOptions = "Center" HorizontalOptions = "FillAndExpand">

        <Label HorizontalOptions = "Center">
            <Label.FormattedText>
                <FormattedString>
                     <Span Text = "Don't have an account?" TextColor = "Gray"></Span>
                     <Span Text = "Register" TextColor = "Gray" FontAttributes = "Bold" TextDecorations = "Underline"></Span>
                </FormattedString>
            </Label.FormattedText>
            <Label.GestureRecognizers>
                <TapGestureRecognizer  Command = "{Binding LoginCommand}"></TapGestureRecognizer>
            </Label.GestureRecognizers>
        </Label>
        
    </StackLayout>
   
</ContentPage>

Логинвиевмодель:

  public class LoginViewModel : INotifyPropertyChanged 
  {

    
        public ICommand LoginCommand { get; private set; }
   

        public event PropertyChangedEventHandler PropertyChanged;



        public LoginViewModel()
        {
              LoginCommand = new Command(async () => await Login());
        }
   
     

        public async Task Login()
        {
            // add your logic here
        }

     
   }

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