如何解决从动态创建的 Blazor 组件订阅事件,以便调用页面可以执行某些操作
我有一个 Blazor Web Assembly .NET 5 托管应用程序,但在处理动态创建的 Blazor 组件时遇到问题。
我的问题的一个例子:
Index.razor 页面:
(这会调用动态组件并通过调用注入的服务 _slideInRenderedOutput
将其呈现给 SlideInService
)
@page "/"
@implements Idisposable
@inject ISlideInService SlideInService
<h1>Hello,world!</h1>
Welcome to your new app.
<TelerikButton Primary="true" OnClick="ToggleComponentSlideIn">Show Simple Form in Slide-In</TelerikButton>
@_slideInRenderedOutput;
<TelerikButton Primary="true" OnClick="Reset">Reset</TelerikButton>
@code
{
private RenderFragment _slideInRenderedOutput;
private async Task ToggleComponentSlideIn(MouseEventArgs obj)
{
_slideInRenderedOutput = SlideInService.Show<SimpleForm>("Test Title").Markup;
}
private async Task Reset(MouseEventArgs obj)
{
SlideInRenderedOutput = null;
}
protected override async Task OnInitializedAsync()
{
Console.WriteLine($"Index.razor: OnInitializedAsync()");
await base.OnInitializedAsync();
}
protected override async Task OnParameteRSSetAsync()
{
Console.WriteLine($"Index.razor: OnParameteRSSetAsync()");
await base.OnParameteRSSetAsync();
}
public void dispose()
{
Console.WriteLine($"Index.razor: dispose()");
}
}
ISlideInService.cs:
public interface ISlideInService
{
/// <summary>
/// Shows a slide-in containing a <typeparamref name="TComponent"/> with the specified <paramref name="title"/>.
/// </summary>
/// <param name="title">Slide-In title.</param>
ISlideInServiceInstance Show<TComponent>(string title) where TComponent : IComponent;
void Close();
}
ISlideInServiceInstance.cs:
public interface ISlideInServiceInstance
{
RenderFragment Markup { get; set; }
}
SlideInService.cs:
public class SlideInService : ISlideInService,ISlideInServiceInstance
{
/// <summary>
/// Shows the slide-in with the component type using the specified title.
/// </summary>
/// <param name="title">Slide-In title.</param>
public ISlideInServiceInstance Show<T>(string title) where T : IComponent
{
return Show<T>(title,new SlideInParameters(),new SlideInoptions());
}
/// <summary>
/// Shows the slide-in with the component type using the specified <paramref name="title"/>,/// passing the specified <paramref name="parameters"/> and setting a custom CSS style.
/// </summary>
/// <param name="contentComponent">Type of component to display.</param>
/// <param name="title">Slide-In title.</param>
/// <param name="parameters">Key/Value collection of parameters to pass to component being displayed.</param>
/// <param name="options">Options to configure the slide-in.</param>
private ISlideInServiceInstance Show(Type contentComponent,string title,SlideInParameters parameters,SlideInoptions options)
{
if (!typeof(IComponent).IsAssignableFrom(contentComponent))
{
throw new ArgumentException($"{contentComponent.FullName} must be a Blazor Component");
}
var slideInInstanceId = Guid.NewGuid();
SlideIn slideInReference = null;
var slideInContent = new RenderFragment(builder =>
{
var i = 0;
builder.OpenComponent(i++,contentComponent);
foreach (var parameter in parameters._parameters)
{
builder.AddAttribute(i++,parameter.Key,parameter.Value);
}
builder.CloseComponent();
});
var slideInInstance = new RenderFragment(builder =>
{
builder.OpenComponent<SlideIn>(0);
builder.AddAttribute(1,"Title",title);
builder.AddAttribute(2,"Options",options);
builder.AddAttribute(3,"ChildContent",slideInContent);
builder.CloseComponent();
});
Markup = slideInInstance;
return this;
}
public RenderFragment Markup { get; set; }
public void Close()
{
Markup = null;
}
}
SlideIn.razor 组件:
@implements Idisposable
@inject ISlideInService SlideInService
<TelerikAnimationContainer @ref="_slideInRef"
Width="@Options.Width"
ParentClass="slide-in"
AnimationType="AnimationType.SlideLeft"
AnimationDuration="600">
<div class="slide-in-content">
<div class="slide-in-header">
<span>@Title</span>
</div>
<CascadingValue Value="this">
@ChildContent
</CascadingValue>
</div>
</TelerikAnimationContainer>
@code {
private TelerikAnimationContainer _slideInRef;
[Parameter]
public string Title { get; set; }
[Parameter]
public SlideInoptions Options { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
public async Task CloseAsync()
{
await _slideInRef.HideAsync();
SlideInService.Close();
StateHasChanged();
}
protected override async Task OnInitializedAsync()
{
Console.WriteLine($"SlideIn.razor: OnInitializedAsync()");
await base.OnInitializedAsync();
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
Console.WriteLine($"SlideIn.razor: OnAfterRenderAsync(firstRender:true)");
await _slideInRef.ShowAsync();
}
else
{
Console.WriteLine($"SlideIn.razor: OnAfterRenderAsync(firstRender:false)");
}
await base.OnAfterRenderAsync(firstRender);
}
protected override async Task OnParameteRSSetAsync()
{
Console.WriteLine($"SlideIn.razor: OnParameteRSSetAsync()");
await base.OnParameteRSSetAsync();
}
public void dispose()
{
Console.WriteLine($"SlideIn.razor: dispose()");
}
}
SimpleForm.razor:
@using System.ComponentModel.DataAnnotations
@implements Idisposable
<div class="slide-in-body">
<EditForm EditContext="@_editContext" OnValidSubmit="@HandleValidSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<label for="clientId">Client Id</label>
<InputText id="clientId" @bind-Value="_exampleModel.ClientId" />
<label for="name">Name</label>
<InputText id="name" @bind-Value="_exampleModel.Name" />
<button type="submit">Submit</button>
</EditForm>
</div>
<div class="slide-in-actions">
<TelerikButton
ButtonType="@ButtonType.Button"
Primary="false"
@onclick="Cancel">
Cancel
</TelerikButton>
<TelerikButton
ButtonType="@ButtonType.Button"
Primary="true"
@onclick="Save"
Enabled="@(_editContext.Validate())">
Save
</TelerikButton>
</div>
@code {
private ExampleModel _exampleModel = new();
private EditContext _editContext;
protected override void OnInitialized()
{
_editContext = new EditContext(_exampleModel);
}
[CascadingParameter]
private SlideIn SlideIn { get; set; }
[Parameter]
public int? ClientId { get; set; }
protected override async Task OnInitializedAsync()
{
Console.WriteLine($"SimpleForm.razor: OnInitializedAsync()");
_exampleModel.ClientId = ClientId.ToString();
await base.OnInitializedAsync();
}
protected override async Task OnParameteRSSetAsync()
{
Console.WriteLine($"SimpleForm.razor: OnParameteRSSetAsync()");
await base.OnParameteRSSetAsync();
}
public void dispose()
{
Console.WriteLine($"SimpleForm.razor: dispose()");
}
public class ExampleModel
{
[required]
public string ClientId { get; set; }
[required]
[StringLength(10,ErrorMessage = "Name is too long.")]
public string Name { get; set; }
}
private void HandleValidSubmit()
{
Console.WriteLine("Form submitted OK");
SlideIn.CloseAsync();
}
private async Task Save(MouseEventArgs obj)
{
var isValid = _editContext?.Validate() ?? false;
if (isValid)
{
Console.WriteLine("Form submitted OK");
await SlideIn.CloseAsync();
}
}
private async Task Cancel(MouseEventArgs obj)
{
await SlideIn.CloseAsync();
}
}
当我单击呈现的 Cancel
上的 SimpleForm
按钮时,它会从其动态 Parent CloseAync
CascadingParameter 上调用 SlideIn
1}} 组件。
然后我想要做的是通知 Index.page(创建动态组件的原始调用站点/页面)动态 SlideIn
组件已被其子 {{1 }} 组件,以便我可以在索引页面上执行一些操作(例如刷新网格)。
我花了一天左右的时间试图实现这一目标,但没有成功,我正在尝试使用动态组件做些什么?
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。