【问题标题】:Update components element from a different component从不同的组件更新组件元素
【发布时间】:2020-06-06 06:11:52
【问题描述】:

我试图从页面更改我的一个组件内的元素的类,但这些类永远不会改变。我在函数里面放了一个Console.Writeline,函数是definitley运行的。

CircleClass 变量默认设置为"danger",并且工作正常,div 以danger class 开头。 console.writeline 确认变量正在被更改,它只是没有更新元素。

组件中的代码:

<div class="circle @CircleClass"></div>

@code {
    private string CircleClass = "danger";

    public void ChangeStatus(int status)
    {
        switch (status)
        {
            case 0:
                CircleClass = "idle";
                break;
            case 1:
                CircleClass = "safety";
                break;
            case 2:
                CircleClass = "danger";
                break;
        }

        Console.WriteLine($"{status} Circle: {CircleClass}");
    }
}

第一次尝试

@page "/"

@Inject Nav nav

<button @onclick="@(e => nav.ChangeStatus(2))">Two</button>

Startup.cs 我添加了这个:

services.AddSingleton<Nav>();

第二次尝试

@page "/"

<button @onclick="@(e => ChangeStatus(2))">Two</button>

private void ChangeStatus(int status)
{
    Nav nav = new Nav();
    nav.ChangeStatus(status);
}

我认为这可能与创建类的新实例有关,该实例无法更改我需要更改的元素的类,尽管我认为使用AddSingleton 时应该解决这个问题。

有谁知道是什么导致了这个问题?


在组件内部调用函数确认该函数确实有效。

组件:

protected override void OnInitialized()
{
    ChangeStatus(1);
}

我正在尝试什么:

Nav.razor

<li id="status">
    <div class="circle @CircleClass"></div>
</li>

@code {
    private string CircleClass = "danger";

    public void ChangeStatus(int status)
    {
        switch (status)
        {
            case 0:
                CircleClass = "idle";
                break;
            case 1:
                CircleClass = "safety";
                break;
            case 2:
                CircleClass = "danger";
                break;
            default:
                CircleClass = "idle";
                break;
        }

        Console.WriteLine($"{status} Circle: {CircleClass}");

        InvokeAsync(() =>
        {
            StateHasChanged();
        });
    }
}

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();
    services.AddServerSideBlazor();

    services.AddSingleton<Nav>();
}

Index.razor

@page "/"

@inject Nav nav 

<button @onclick="@(e => nav.ChangeStatus(0))">Zero</button>
<button @onclick="@(e => nav.ChangeStatus(1))">One</button>
<button @onclick="@(e => nav.ChangeStatus(2))">Two</button>

在我上面的代码示例中,我使用按钮尝试从页面运行导航组件中的功能,但最终我将在不同的地方运行这些功能,这些地方在没有用户直接输入的情况下不会是页面。


Nav 组件是在我的MainLayout 中定义/创建的,它不直接应用于Index 页面。

【问题讨论】:

    标签: blazor


    【解决方案1】:

    你需要做一个可以帮助管理组件的服务。

    首先:

    • 创建服务并将更新组件的函数移动到它(在本例中为ChangeStatus())。
    • 向您的新服务添加一个事件,并在 ChangeStatus() 函数结束时触发它。

    services/MyService.cs

    using System;
    
    namespace MyAppName.Services
    {
        public delegate void MyEventHandler();
    
        public class MyService
        {
            public event MyEventHandler MyEvent;
            public string CircleClass = "danger";
    
            public void ChangeStatus(int status)
            {
                switch (status)
                {
                    case 0:
                        CircleClass = "idle";
                        break;
                    case 1:
                        CircleClass = "safety";
                        break;
                    case 2:
                        CircleClass = "danger";
                        break;
                }
    
                // Fire event
                MyEvent?.Invoke();
            }
        }
    }
    
    

    其次:

    • 在您的 blazor 应用中将服务添加为 Singleton
    • 为方便访问,请将 Services 命名空间添加到您的 _Imports.razor 文件中。

    添加服务

    // In Blazor Server-Side
    // open Startup.cs and add:
    
    public void ConfigureServices(IServiceCollection services)
    {
        // [..]
    
        services.AddSingleton<MyService>();
    }
    
    // In Blazor WebAssembly
    // open Program.cs and add:
    
    public static async Task Main(string[] args)
    {
        // [..]
    
        builder.Services.AddSingleton<MyService>();
    }
    
    

    将服务添加到 _Imports.razor

    // This will only work if the namespace
    // for your service is the MyAppName.Services.
    // If you put your service in the Services folder
    // you should be fine unless you renamed the namespace.
    @using MyAppName.Services
    

    第三:

    • 将服务注入您的组件。
    • 在您的组件中订阅事件并创建一个函数以在事件触发时运行StateHasChanges()

    Component.razor

    // At the top:
    @inject MyService myService
    
    // Subscribe to event and create function
    @code {
        protected override void OnInitialized()
        {
            myService.MyEvent+= UpdateState;
        }
    
        private void UpdateState()
        {
            // Need to use InvokeAsync, atleast
            // on Blazor Server-Side
            InvokeAsync(() =>
            {
                StateHasChanged();
            });
        }
    }
    

    最后:

    • 从其他地方(在本例中,从页面)在服务中运行 ChangeStatus() 函数

    Index.razor

    @page "/"
    
    @inject MyService myService
    
    <button @onclick="@(e => myService.ChangeStatus(0))">Test 0</button>
    <button @onclick="@(e => myService.ChangeStatus(1))">Test 1</button>
    

    【讨论】:

      【解决方案2】:

      你可以做这样的事情。我认为您不需要导航服务。您可以从页面本身调用和更改类值。

      索引页内

      HTML

      <Nav @ref="navComp"></Nav>
      
      <button @onclick="@(e => navComp.ChangeStatus(0))">Zero</button>
      <button @onclick="@(e => navComp.ChangeStatus(1))">One</button>
      <button @onclick="@(e => navComp.ChangeStatus(2))">Two</button>
      

      C# 代码

      @code {
      Nav navComp;
      
          //other code
      }
      

      导航组件内部

      HTML

      <h3>Nav</h3>
      <li id="status">
          <div class="circle @CircleClass"></div>
      </li>
      

      C# 代码

      @code {
          private string CircleClass = "danger";
      
          public void ChangeStatus(int status)
          {
              switch (status)
              {
                  case 0:
                      CircleClass = "idle";
                      break;
                  case 1:
                      CircleClass = "safety";
                      break;
                  case 2:
                      CircleClass = "danger";
                      break;
                  default:
                      CircleClass = "idle";
                      break;
              }
      
              Console.WriteLine($"{status} Circle: {CircleClass}");
      
              InvokeAsync(() =>
              {
                  StateHasChanged();
              });
          }
      }
      

      你可以在这里看到输出..

      【讨论】:

      • 这可行,但在我的情况下,&lt;Nav&gt; 元素并未直接应用于Index 页面。当元素不是直接在该特定页面上而是在其布局中(我有&lt;Nav&gt; element in MainLayout`)时,有没有办法访问元素的功能?
      猜你喜欢
      • 2020-08-08
      • 2018-04-13
      • 2017-07-11
      • 2017-05-17
      • 2016-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-06
      相关资源
      最近更新 更多