练习 - 在 Blazor 应用程序中共享数据

已完成

现在,应用已连接到数据库,是时候添加订购和配置客户的披萨这一功能了。

Blazing Pizza 希望你生成允许客户更改其特价披萨尺寸的功能。 你需要存储订单,并且已选择在容器服务中存储应用程序状态。

在本练习中,你将向新的订单配置组件传递数据,并了解如何在 OrderState 作用域服务中存储应用的状态。

添加新的订单配置对话框

  1. 如果应用仍在运行,请停止它。

  2. 在 Visual Studio Code 中,右键单击 Shared 文件夹,然后选择“新建文件”。

  3. 输入 ConfigurePizzaDialog.razor 作为文件名。

  4. 为新的订购组件的 UI 输入以下代码:

    @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. 通过允许客户选择披萨的 <li> 标记,允许网页调用服务器端 ShowConfigurePizzaDialog 方法。 将 <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. 选择披萨并观看新对话框的出现。

    Screenshot showing the pizza ordering dialog.

处理订单的状态

此时,应用会显示配置对话框,但不允许取消或继续订购披萨。 若要管理订单的状态,需要添加新的订单状态容器服务。

  1. 如果应用仍在运行,请停止它。

  2. 在 BlazingPizza 文件夹中创建新文件夹。 将其命名为 Services。

  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. @code 块中移除 configuringPizzashowingConfigureDialogShowConfigurePizzaDialog()。 它现在应如下所示:

    @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 类中有两种我们尚未使用的方法。 CancelConfigurePizzaDialogConfirmConfigurePizzaDialog 方法将关闭对话框,并在客户确认订购后将披萨添加到 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 方法。 在文件资源管理器中,展开“页面”。 然后选择“Index.razor”。

  6. 更改对 ConfigurePizzaDialog 组件的调用的代码:

        <ConfigurePizzaDialog
          Pizza="OrderState.ConfiguringPizza"
          OnCancel="OrderState.CancelConfigurePizzaDialog"
          OnConfirm="OrderState.ConfirmConfigurePizzaDialog" />
    
  7. 选择 F5 或“运行”。 然后选择“开始调试”。

应用现在应允许客户取消订单或向订单中添加已配置的披萨。 当披萨大小发生变化时,我们无法显示当前订单或更新价格。 我们将在下一练习中添加这些功能。