Упражнение. Предоставление общего доступа к данным в приложениях Blazor

Завершено

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

Blazing Pizza хочет, чтобы вы создали возможность для клиентов изменять размер их особых пицц. Необходимо хранить заказ и сохранять состояние приложения в сервисе контейнеров.

В этом упражнении вы передаете данные в новый компонент конфигурации заказа и увидите, как сохранить состояние приложения в службе с областью OrderState.

Добавление диалогового окна настройки нового заказа

  1. Остановите приложение, если оно по-прежнему запущено.

  2. В Visual Studio Code щелкните правой кнопкой мыши папку Shared и выберите Новый файл.

  3. Введите ConfigurePizzaDialog.razor в качестве имени файла.

  4. Введите этот код для пользовательского интерфейса нового компонента заказов:

    @inject HttpClient HttpClient
    
    <div class="dialog-container">
        <div class="dialog">
            <div class="dialog-title">
                <h2>@Pizza.Special.Name</h2>
                @Pizza.Special.Description
            </div>
            <form class="dialog-body">
                <div>
                    <label>Size:</label>
                    <input type="range" min="@Pizza.MinimumSize" max="@Pizza.MaximumSize" step="1" />
                    <span class="size-label">
                        @(Pizza.Size)" (£@(Pizza.GetFormattedTotalPrice()))
                    </span>
                </div>
            </form>
    
            <div class="dialog-buttons">
                <button class="btn btn-secondary mr-auto" >Cancel</button>
                <span class="mr-center">
                    Price: <span class="price">@(Pizza.GetFormattedTotalPrice())</span>
                </span>
                <button class="btn btn-success ml-auto" >Order ></button>
            </div>
        </div>
    </div>
    

    Этот компонент представляет собой диалоговое окно, показывающее выбранную специальную пиццу и позволяющее клиенту выбрать размер пиццы.

    Компоненту необходимо использовать специальную пиццу из компонента индексной страницы для доступа к значениям членов пиццы.

  5. Добавьте блок Blazor @code, чтобы разрешить передаче параметров в компонент:

    @code {
        [Parameter] public Pizza Pizza { get; set; }
    }
    

Заказ пиццы

Когда клиент выбирает пиццу, диалоговое окно должно позволить им изменить размер пиццы. Давайте улучшим элемент управления index.razor, чтобы добавить интерактивные возможности.

  1. В проводнике разверните страницы и выберите Index.razor.

  2. Добавьте этот код в блок @code в переменной List<PizzaSpecial>:

    Pizza configuringPizza;
    bool showingConfigureDialog;
    
  3. Добавьте этот код для создания пиццы в методе OnInitializedAsync():

    void ShowConfigurePizzaDialog(PizzaSpecial special)
    {
        configuringPizza = new Pizza()
        {
            Special = special,
            SpecialId = special.Id,
            Size = Pizza.DefaultSize
        };
    
        showingConfigureDialog = true;
    }
    
  4. Позвольте веб-странице вызывать метод ShowConfigurePizzaDialog на стороне сервера, позволяя клиентам выбрать тег <li> для пиццы. Замените строку <li> следующим кодом:

    <li @onclick="@(() => ShowConfigurePizzaDialog(special))" style="background-image: url('@special.ImageUrl')">
    

    Когда клиент выбирает пиццу, сервер выполняет метод ShowConfigurePizzaDialog, который создает пиццу со специальными данными пиццы и задает для переменной showingConfigureDialog значение true.

  5. На странице нужен способ отображения нового компонента ConfigurePizzaDialog. Добавьте этот код над блоком @code:

    @if (showingConfigureDialog)
    {
        <ConfigurePizzaDialog Pizza="configuringPizza" />
    }
    

    Теперь весь файл index.razor должен выглядеть следующим образом:

    @page "/"
    @inject HttpClient HttpClient
    @inject NavigationManager NavigationManager
    
    <div class="main">
        <h1>Blazing Pizzas</h1>
        <ul class="pizza-cards">
        @if (specials != null)
        {
            @foreach (var special in specials)
            {
              <li @onclick="@(() => ShowConfigurePizzaDialog(special))" style="background-image: url('@special.ImageUrl')">
                <div class="pizza-info">
                <span class="title">@special.Name</span>
                @special.Description
                <span class="price">@special.GetFormattedBasePrice()</span>
                </div>
              </li>
            }
        }
        </ul>
    </div>
    
    @if (showingConfigureDialog)
    {
        <ConfigurePizzaDialog Pizza="configuringPizza" />
    }
    
    @code {
        List<PizzaSpecial> specials = new();
        Pizza configuringPizza;
        bool showingConfigureDialog;
    
        protected override async Task OnInitializedAsync()
        {
            specials = await HttpClient.GetFromJsonAsync<List<PizzaSpecial>>(NavigationManager.BaseUri + "specials");
        }
    
        void ShowConfigurePizzaDialog(PizzaSpecial special)
        {
            configuringPizza = new Pizza()
            {
                Special = special,
                SpecialId = special.Id,
                Size = Pizza.DefaultSize
            };
    
            showingConfigureDialog = true;
        }
    }
    
  6. Выберите F5 или выберите Выполнить. Затем выберите Начать отладку.

  7. Выберите пиццу и просмотрите новое диалоговое окно.

    снимок экрана: диалоговое окно заказа пиццы.

Управлять состоянием заказа

На данный момент приложение отображает диалоговое окно конфигурации, но не позволяет отменить или перейти к заказу пиццы. Чтобы управлять состоянием заказа, добавьте новую службу управления состоянием заказа.

  1. Остановите приложение, если оно по-прежнему запущено.

  2. Создайте новую папку в папке BlazingPizza. Назовите это службы.

  3. Создайте новый файл в папке Services. Назовите его OrderState.cs.

  4. Введите этот код для класса:

    namespace BlazingPizza.Services;
    
    public class OrderState
    {
        public bool ShowingConfigureDialog { get; private set; }
        public Pizza ConfiguringPizza { get; private set; }
        public Order Order { get; private set; } = new Order();
    
        public void ShowConfigurePizzaDialog(PizzaSpecial special)
        {
            ConfiguringPizza = new Pizza()
            {
                Special = special,
                SpecialId = special.Id,
                Size = Pizza.DefaultSize,
                Toppings = new List<PizzaTopping>(),
            };
    
            ShowingConfigureDialog = true;
        }
    
        public void CancelConfigurePizzaDialog()
        {
            ConfiguringPizza = null;
    
            ShowingConfigureDialog = false;
        }
    
        public void ConfirmConfigurePizzaDialog()
        {
            Order.Pizzas.Add(ConfiguringPizza);
            ConfiguringPizza = null;
    
            ShowingConfigureDialog = false;
        }
    }
    

    Обратите внимание, что в данный момент в компоненте index.razor есть код, который можно переместить в новый класс. Следующий шаг — сделать эту службу доступной в приложении.

  5. В проводнике выберите Program.cs.

  6. В части файла со строками, начинающимися с builder.Services., добавьте следующую строку:

    builder.Services.AddScoped<OrderState>();
    

    Из предыдущего упражнения мы добавили здесь контекст базы данных. Этот код добавляет новую службу OrderState. Теперь этот код можно использовать в компоненте index.razor.

  7. Добавьте следующую using директиву в начало файла. Эта директива обрабатывает все ссылки на класс OrderState.

    using BlazingPizza.Services;
    
  8. В проводнике разверните страницы и выберите Index.razor.

  9. В верхней части файла в @inject NavigationManager NavigationManagerдобавьте следующий код:

    @using BlazingPizza.Services
    @inject OrderState OrderState
    
  10. Удалите configuringPizza, showingConfigureDialogи ShowConfigurePizzaDialog() из блока @code. Теперь он должен выглядеть следующим образом:

    @code {
        List<PizzaSpecial> specials = new List<PizzaSpecial>();
    
        protected override async Task OnInitializedAsync()
        {
            specials = await HttpClient.GetFromJsonAsync<List<PizzaSpecial>>(NavigationManager.BaseUri + "specials");
        }
    }
    

    Теперь возникают ошибки, когда код ссылается на удаленные элементы.

  11. Измените вызов на ShowConfigurePizzaDialog(special)), чтобы использовать версию OrderState:

    <li @onclick="@(() => OrderState.ShowConfigurePizzaDialog(special))" style="background-image: url('@special.ImageUrl')">
    
  12. Измените ссылку на логический showingConfigureDialog:

    @if (OrderState.ShowingConfigureDialog)
    
  13. Изменение параметра с помощью configuringPizza:

    <ConfigurePizzaDialog Pizza="OrderState.ConfiguringPizza" />
    
  14. Выберите F5 или выберите Выполнить. Затем выберите Начать отладку.

    Если все правильно, вы не должны видеть никакой разницы. Диалоговое окно отображается так же, как и раньше.

Отмена и выполнение заказов на пиццу

Возможно, в классе OrderState есть два метода, которые еще не используются. Методы CancelConfigurePizzaDialog и ConfirmConfigurePizzaDialog закрывают диалоговое окно и добавляют пиццу в объект Order, после того как клиент подтвердит заказ. Давайте подключим эти методы к кнопкам диалогового окна конфигурации.

  1. Остановите приложение, если оно по-прежнему запущено.

  2. В проводнике разверните общие. Затем выберите ConfigurePizzaDialog.razor.

  3. В блоке @code добавьте два новых параметра:

    @code {
       [Parameter] public Pizza Pizza { get; set; }
       [Parameter] public EventCallback OnCancel { get; set; }
       [Parameter] public EventCallback OnConfirm { get; set; }
    }
    `` `
    
    
  4. Теперь к кнопкам могут быть добавлены директивы @onclick. Измените нынешний код для кнопок диалогового окна на следующую разметку:

    <div class="dialog-buttons">
        <button class="btn btn-secondary mr-auto" @onclick="OnCancel">Cancel</button>
        <span class="mr-center">
            Price: <span class="price">@(Pizza.GetFormattedTotalPrice())</span>
        </span>
        <button class="btn btn-success ml-auto" @onclick="OnConfirm">Order ></button>
    </div>
    
  5. Последний шаг — передать методы OrderState для отмены и подтверждения заказов. В проводнике разверните Pages. Затем выберите Index.razor.

  6. Измените код для вызова компонента ConfigurePizzaDialog:

    <ConfigurePizzaDialog
        Pizza="OrderState.ConfiguringPizza"
        OnCancel="OrderState.CancelConfigurePizzaDialog"
        OnConfirm="OrderState.ConfirmConfigurePizzaDialog" />
    
  7. Выберите F5 или выберите Выполнить. Затем выберите Начать отладку.

Теперь приложение должно позволить клиентам отменить или добавить настроенную пиццу в заказ. У нас нет способа показать текущий заказ или обновить цены при изменении размера пиццы. Мы добавим эти функции в следующем упражнении.