Евгений Колесников cbd87e11e5 maui 3 mesiacov pred
..
img cbd87e11e5 maui 3 mesiacov pred
README.md cbd87e11e5 maui 3 mesiacov pred
SimpleMaui.zip cbd87e11e5 maui 3 mesiacov pred

README.md

Лекция: Разработка приложения "Меню ресторана" на .NET MAUI

Введение в .NET MAUI

.NET MAUI (Multi-platform App UI) - это кроссплатформенный фреймворк для создания нативных мобильных и десктопных приложений. Основные компоненты:

XAML - язык разметки для создания UI

C# - бизнес-логика

MVVM (Model-View-ViewModel) - архитектурный паттерн

Библиотеки - для работы с сетью, БД и т.д.

Поддерживаемые платформы

  • Мобильные: iOS, Android
  • Десктоп: Windows (WinUI), macOS (Catalyst)
  • В будущем: Linux (в разработке)

Ключевые особенности

  • Единая кодовая база на C#
  • Использование XAML для UI
  • Доступ к нативным API платформ
  • Горячая перезагрузка (Hot Reload)
  • Встроенная поддержка MVVM

.NET MAUI представляет собой мощную эволюцию кроссплатформенных инструментов Microsoft, сочетающую в себе:

  • Многолетний опыт Xamarin
  • Мощь современного .NET
  • Гибкость кроссплатформенной разработки
  • Производительность нативных приложений

Это технология, которая позволяет создавать по-настоящему нативные приложения с экономией времени и ресурсов, что делает ее отличным выбором для современных мобильных и десктопных проектов.

Оснавная структура страницы

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="SimpleMauiMySQL.MainPage"
             Title="Меню ресторана">

    <Grid RowDefinitions="*, Auto">
        <!-- Область меню (верхняя часть) -->
        <CollectionView Grid.Row="0"
                       ItemsSource="{Binding MenuProducts}"
                       SelectionMode="None">
        </CollectionView>

        <!-- Область корзины (нижняя часть) -->
        <Frame Grid.Row="1"
               BackgroundColor="#f0f0f0"
               Padding="10">
        </Frame>
    </Grid>
</ContentPage>

Создание модели данных

Создаем класс Product.cs для работы с данными из API:

public class Product
{
    public int id { get; set; }
    public string title { get; set; }
    public decimal price { get; set; }
       
    
    public int Quantity { get; set; }
}

Объяснение:

Базовые свойства соответствуют полям из API

Проверить данные , которые находятся в api можно на сайте https://reqbin.com/

Инициализация в MainPage:

public partial class MainPage : ContentPage
{
    public ObservableCollection<Product> MenuProducts { get; } = new();
    
    public MainPage()
    {
        InitializeComponent();
        BindingContext = this;
    }
}

Загрузка и отображение продуктов

Метод загрузки:

private async void LoadMenu()
{
    try
    {
        using var client = new HttpClient();
        var json = await client.GetStringAsync("https://restaurant.kolei.ru");
        var products = JsonSerializer.Deserialize<List<Product>>(json);
        
        foreach (var p in products)
        {
            MenuProducts.Add(p);
        }
    }
    catch (Exception ex)
    {
        await DisplayAlert("Ошибка", ex.Message, "OK");
    }
}

Вызываем в конструкторе:

public MainPage()
{
    InitializeComponent();
    BindingContext = this;
    LoadMenu(); // Добавляем вызов загрузки
}

Добавление кнопок управления количества

<CollectionView.ItemTemplate>
    <DataTemplate>
        <Frame Margin="10" Padding="10">
            <Grid ColumnDefinitions="*,Auto,Auto,Auto,Auto">
                <!-- Название и цена -->
                <Label Text="{Binding title}" FontSize="16"/>
                <Label Grid.Column="1" Text="{Binding price, StringFormat='{0:C}'}"/>
                
                <!-- Кнопки управления -->
                <Button Grid.Column="2" Text="-" 
                        CommandParameter="{Binding .}"
                        Clicked="DecreaseProduct_Clicked"/>
                
                <Label Grid.Column="3" Text="{Binding Quantity}"
                       VerticalOptions="Center"/>
                
                <Button Grid.Column="4" Text="+" 
                        CommandParameter="{Binding .}"
                        Clicked="AddToCart_Clicked"/>
            </Grid>
        </Frame>
    </DataTemplate>
</CollectionView.ItemTemplate>

Реализуем логику корзины

Добавляем коллекцию корзины:

public ObservableCollection<Product> CartItems { get; } = new();

Методы добавления/удаления:

private void AddToCart_Clicked(object sender, EventArgs e)
{
    if (sender is Button { BindingContext: Product product })
    {
        var existing = CartItems.FirstOrDefault(p => p.id == product.id);
        if (existing != null)
            existing.Quantity++;
        else
        {
            product.Quantity = 1;
            CartItems.Add(product);
        }
    }
}

private void DecreaseProduct_Clicked(object sender, EventArgs e)
{
    if (sender is Button { BindingContext: Product product })
    {
        var item = CartItems.FirstOrDefault(p => p.id == product.id);
        if (item != null)
        {
            if (item.Quantity > 1)
                item.Quantity--;
            else
                CartItems.Remove(item);
        }
    }
}

Добавляем отображение корзины

Обновляем Frame корзины:

<Frame Grid.Row="1" BackgroundColor="#f0f0f0" Padding="10">
    <StackLayout>
        <Label Text="Ваша корзина:" FontAttributes="Bold"/>
        <Label Text="{Binding CartContent}"/>
        <Label Text="{Binding TotalAmount, StringFormat='Итого: {0:C}'}"
               FontAttributes="Bold"/>
        
        <Button Text="Очистить корзину"
                Clicked="ClearCart_Clicked"/>
    </StackLayout>
</Frame>

Реализуем логику отображения корзины

Вычисляемые свойства:

public string CartContent => 
    CartItems.Count == 0 ? "Корзина пуста" : 
    string.Join("\n", CartItems.Select(i => $"{i.title} - {i.Quantity} шт."));

public decimal TotalAmount => 
    CartItems.Sum(item => item.price * item.Quantity);

Метод очистки:

private void ClearCart_Clicked(object sender, EventArgs e)
{
    CartItems.Clear();
}

Добавляем обновление интерфейса

Метод обновления:

private void UpdateCart()
{
    OnPropertyChanged(nameof(CartContent));
    OnPropertyChanged(nameof(TotalAmount));
}

Обновляем методы работы с корзиной:

private void AddToCart_Clicked(object sender, EventArgs e)
{
    // ... существующая логика ...
    UpdateCart(); // Добавляем в конце
}

private void DecreaseProduct_Clicked(object sender, EventArgs e)
{
    // ... существующая логика ...
    UpdateCart(); // Добавляем в конце
}

private void ClearCart_Clicked(object sender, EventArgs e)
{
    CartItems.Clear();
    UpdateCart(); // Добавляем вызов
}

При скачивании проекта введите команду dotnet workload restore для того чтобы скачать все зависимости и пакеты.

Визуал проекта на Windows:

Если вы хотите запустить проект на Android, вам понадобится:

Устройство и USB-провод.

Включить режим разработчика на телефоне.

Нажмите 11 раз на версию телефона.

Включите отладку по USB.

Подключите устройство и найдите его в списке, затем запустите проект.

Также можно запустить проект с помощью эмулятора. Для этого выберите соответствующую опцию:

После этого начнется скачивание эмулятора и необходимых программ.

Визуал проекта на Android: