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

已完成

现在,你的应用已连接到数据库,接下来可以添加订购和配置客户的披萨的功能。

Blazing Pizza 希望你能够为客户构建改变其特殊比萨饼的大小的能力。 需要存储订单,并且已选择将应用程序状态存储在容器服务中。

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

添加新订单配置对话框

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

  2. 在 Visual Studio Code 中,右键单击 共享文件夹 并选择“ 新建文件”。

  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. 在文件资源管理器中,展开 Pages,然后选择 Index.razor

  2. 将这段代码添加到List<PizzaSpecial>变量下的@code块中:

        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使用特殊披萨数据创建披萨的方法,并将变量true设置为 showingConfigureDialog

  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. 在文件资源管理器中,展开 Pages,然后选择 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 或选择 “运行”。 然后选择“ 开始调试”。

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