DynamicComponent只有当method和DynamicComponent在同一个组件中时才有效



我的问题如下:

我需要根据来自不同组件的方法动态显示内容DynamicComponent标签在。

这是故意的还是我做错了什么?

我代码:

Platform.razor:

<a href="" @onclick:preventDefault @onclick="@(()=>ChangePage("ListLinks"))>
public Type? selectedPage = typeof(Empty);
public void ChangePage(string page)
{
selectedPage = page.Length > 0 ? Type.GetType($"Namespace.Shared.{page}") : null;
}

Home.razor:

Platform platform = new Platform();

<DynamicComponent Type="@platform.selectedPage"></DynamicComponent>

当我在同一个组件中调用方法时,一切正常,但这不是我需要的。

这一行:

Platform platform = new Platform();

创建一个新的Platform实例,该实例与Renderer创建的实例没有连接。你不能管理组件实例。

组件之间的通信可以使用DI服务。

下面的一些代码演示了您想要做的事情:

第一个服务:

public class PlatformService
{
public Type? Component { get; private set; }
public event EventHandler? ComponentChanged;

public void SetComponent(Type type)
{
this.Component= type;
this.ComponentChanged?.Invoke(this, EventArgs.Empty);
}
}

Program中注册为作用域,因此它在用户SPA实例的生命周期内持续存在。

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
builder.Services.AddScoped<PlatformService>();

改变组件类型的组件:

@inject PlatformService service
<h3>ComponentSelector</h3>
<div class="m-2 p-2">
<button class="btn btn-primary" @onclick="() => Change(typeof(Counter))"> Counter </button>
<button class="btn btn-primary" @onclick="() => Change(typeof(FetchData))"> FetchData </button>
</div>
@code {
private void Change(Type type)
=> service.SetComponent(type);
}

和Index来演示它。注意,它实现了一个注册在服务事件上的事件处理程序来驱动UI更新。

@page "/"
@inject PlatformService service
@implements IDisposable
<PageTitle>Index</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
<ComponentSelector />
<SurveyPrompt Title="How is Blazor working for you?" />
@if (service.Component is not null)
{
<DynamicComponent Type="service.Component" />
}
@code {
protected override void OnInitialized()
=> this.service.ComponentChanged += this.OnUpdated;
private void OnUpdated(object? sender, EventArgs e)
=> this.InvokeAsync(StateHasChanged);
public void Dispose()
=> this.service.ComponentChanged -= this.OnUpdated;
}

正如您所注意到的,如果您将该方法放在同一个组件中,它就会起作用,而一旦您将它放到子级别,它就不起作用了。这是故意的。

让我们假设你有以下结构:Parent.razor

<h1>@Text</h1>
<Child Text="@text">/
@code {
private string Text = "Hello World";
}

如果在子组件中更新text,父组件将而不是查看更改:

Child.razor


<button @onclick="() =>Text = string.Empty">Click Me</button>
@code {
[Parameter]
public string Text { get; set; }= "";
}

点击"点击我"不会改变父组件的标题。这同样适用于您的示例。

现在,我们如何使它工作?最直接的方法是在动态组件发生变化时触发一个事件,父组件会监听该事件。为此,您还可以使用事件(此特殊表单是双向绑定:https://blazor-university.com/components/two-way-binding/)

[Parameter]
public Type SelectedPage { get; set; } = typeof(Empty);
[Parameter]
public EventCallback<Type> SelectedPageChanged { get; set; }
public async Task ChangePage(string page)
{
selectedPage = page.Length > 0 ? Type.GetType($"Namespace.Shared.{page}") : null;
await SelectedPageChanged.InvokeAsync(selectedPage);
}

我不确定以下内容是否适用于DynamicComponents。

<DynamicComponent @bind-Type="@platform.selectedPage"></DynamicComponent>

如果这不起作用,你可以回退到这个:

Platform.razor

<DynamicComponent Type="@platform.SelectedPage" Parameters="@dynamicParameters"/>
@code {
private Dictionary<string, object> dynamicComponentParameters = new();
protected override void OnInitialized()
{
dynamicComponentParameters.Add("SelectedPageChanged", EventCallback.Factory.Create<Type>(this, SelectedTypeChanged));
}
private void SelectedTypeChanged(Type newType)
{
// After the method a re-render will be triggered
platForm.SelectedPage = newType;
}
}

相关内容

  • 没有找到相关文章

最新更新