Blazor组件需要修改父组件的值

Mer*_*n04 6 c# razor blazor

我的 Blazor 应用程序中有这两个组件:

组件1.剃须刀:

<CascadingValue Value=this>
    <Component2/>
</CascadingValue>

<p>@DisplayedText</p>

@code {
    public string DisplayedText = string.Empty;
}
Run Code Online (Sandbox Code Playgroud)

组件2.剃刀:

<button @onclick=@(e => { C1.DisplayedText = "testing"; })>Set DisplayedText</button>

@code {
    [CascadingParameter]
    public Component1 C1 { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

p当我单击“设置显示文本”按钮时,元素中的文本Component1应更改为testing,但事实并非如此。我怎样才能解决这个问题?

Isa*_*aac 10

@Merlin04,这是对级联值功能的滥用和误用。通常,父组件通过组件参数与其子组件进行通信。

您无法从后代更新级联值。

错误的...

下面的代码片段展示了一个更好的解决方案,根据您所做的,尽管它不是最佳的,因为您的代码和我的代码也从方法更新属性,而事实上,我们应该直接更改属性的值,而不是通过中介代码(即方法)

Component2.razor

<button @onclick="@(() => SetDisplayedText.InvokeAsync("testing"))">Set 
                                                 DisplayedText</button>

@code {
   [Parameter]
   public EventCallback<string> SetDisplayedText { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

Component1.razor

<Component2 SetDisplayedText="@SetDisplayedText"/>

<p>@DisplayedText</p>

@code {
    private string DisplayedText = string.Empty;

    public void SetDisplayedText(string newText)
   {
       DisplayedText = newText;
   }
}
Run Code Online (Sandbox Code Playgroud)

请注意,调用 StateHasChanged 方法不是必需的,因为这是使用 EventCallback“委托”时获得的好处

希望这可以帮助...


Isa*_*aac 9

Merlin04,以下代码片段演示了如何做到这一点。请注意,这实际上是一个非常简单的示例,但它展示了当远程组件之间需要通信时应如何编码。

这是代码,复制并运行它,如果您有更多问题,请随时询问。

消息服务.cs

 public class MessageService
{
    private string message;
    public string Message
    {
        get => message;
        set
        {
            if (message != value)
            {
                message = value;
                if (Notify != null)
                {
                     Notify?.Invoke();
                }

            }
        }
    }

    public event Action Notify;
}
Run Code Online (Sandbox Code Playgroud)

注意:服务是一个普通的类...它为其他对象提供服务,应该在 Startup.ConfigureServices 方法中将其添加到 DI 容器中,以使其可供请求客户端使用。添加以下内容:到ConfigureServices方法:

 services.AddScoped<MessageService>();
Run Code Online (Sandbox Code Playgroud)

注意:正如您所看到的,我定义了一个 Action 类型的事件委托,当用户在 Component3 中的文本框中键入文本时,该事件委托从属性的 set 访问器中调用。触发此委托会导致 Components3 输入的文本显示在作为 Component2 父级的 Index 组件中(请参见下面的代码)。

索引剃刀

@page "/"

@inject MessageService MessageService
@implements IDisposable

<p>I'm the parent of Component2. I've got a message from my grand child: 
                                            @MessageService.Message</p>

<Component2 />

@code {
protected override void OnInitialized()
{
    MessageService.Notify += OnNotify;
}

public void OnNotify()
{
    InvokeAsync(() =>
    {
        StateHasChanged();
    });
 }

 public void Dispose()
 {
    MessageService.Notify -= OnNotify;
 }
}
Run Code Online (Sandbox Code Playgroud)

请注意,我们直接绑定到 MessageService.Message 属性,但必须调用 StateHasChanged 方法来刷新文本的显示。

Component2.razor

<h3>Component2: I'm the parent of component three</h3>
<Component3/>

@code {

}
Run Code Online (Sandbox Code Playgroud)

Component3.razor

@inject MessageService MessageService

<p>This is component3. Please type a message to my grand parent</p>
<input placeholder="Type a message to grandpa..." type="text" 
@bind="@MessageService.Message" @bind:event="oninput" />
Run Code Online (Sandbox Code Playgroud)

请注意,在 Component3 中,我们将 MessageService.Message 绑定到文本框,并且每次按下键盘时都会发生绑定(输入事件与更改事件)。

以上就是全部内容,希望对您有所帮助,如有任何问题,请随时提出。

  • 感谢 @enet 提供的这个示例,我试图找到后代在 blazor 中调用祖先的方法。这是我在阅读示例后找到的微软链接:“内存状态容器服务” https://learn.microsoft.com/en-us/aspnet/core/blazor/state-management?view=aspnetcore-5.0&amp;pivots =web assembly#in-memory-state-container-service-wasm 以及第三方库的这个 https://jonhilton.net/blazor-state-management/ (2认同)