如何在 Blazor 中使用 RenderTreeBuilder for RenderFragment<>



我正在RenderFragment参数中实现EventCallback,以启用外部关闭按钮在自定义组件中触发事件:

public RenderFragment<IElementInfo>? ContentTemplate { get; set; }

这是接口:

public interface IElementInfo
{
EventCallback CloseCallback { get; }
}

使用:

<ContentTemplate>
<button type="button"
@onclick="@(async () =>
await RaiseCallback(context.CloseCallback))">
Cancel
</button>
</ContentTemplate>

[edit]这是编译器为上述用途生成的:

__builder.AddAttribute<ClosedEventArgs>(22, "Closed", RuntimeHelpers.TypeCheck<EventCallback<ClosedEventArgs>>(EventCallback.Factory.Create<ClosedEventArgs>((object) this, new Action(OnClosed))));

[结束编辑]

需要更多的代码来将其连接起来事实上它是有效的

我想做的是添加一个简单的方法来传递标题,并使用RenderTreeBuilder手动连接剃刀组件。以下是非通用RenderFragment:的工作版本

[编辑]

public void Show(string? title, Type contentType)
{
if (contentType.BaseType != typeof(ComponentBase))
throw new ArgumentException
($"{contentType.FullName} must be a Blazor Component");
RenderFragment content = x =>
{
x.OpenComponent(1, contentType);
x.CloseComponent();
};
Show(new Options
{
HeaderText = title,
ContentTemplate = content
});
}
public void Show(Options options)
{
Container container = new Container(options, _provider);
_contents.Add(container);
// notify new content
OnUpdated?.Invoke();
}

示例用法:

Service.Show(
"Sample Title",
typeof(SampleRazorFile));
// where SampleRazorFile is a seperate razor file

[结束编辑]

我感到困惑的地方是用RenderTreeBuilder来更改通用RenderFragment<IElementInfo>

[编辑]

问题是关于RenderTreeBuilder——它能返回Renderfragment<TValue>类型吗?

[结束编辑]

几乎没有关于这项具体任务的信息。有人做过这样的事情吗?有什么建议吗?

我已经得出结论,你不能这么做。我添加了支持RenderFragmentRenderFragment<TValue>的解决方案

实际上,解决方案出乎意料地简单——将RenderFragment强制转换为泛型类型。

因此,对于我上面的例子,答案如下:

ContentTemplate = (RenderFragment<IElementInfo>)(_context =>
builder =>
{
builder.OpenElement(2, "div");
// trimmed...
builder.CloseElement();
}
);

我发现这个解决方案的方式是启用Roslyn生成的文件的发射。将以下内容添加到项目文件中:

<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
</PropertyGroup>

希望这能帮助到别人!

我不完全确定您的上下文以及您是否正确。你没有设置";上下文";在外部,您可以在组件中设置它,并将它传递给外部RenderFragment块。

以下是组件在FetchData中显示WeatherForecast行的一些代码,该代码演示了如何在RenderFragment块中使用RenderFragment<>

<h3>ListOfWeather</h3>
<table class="table">
<thead>
@this.HeaderTemplate
</thead>
@this.Rows
</table>
@code {
[Parameter] public List<WeatherForecast> ForecastList { get; set; } = new List<WeatherForecast>();
[Parameter] public RenderFragment<WeatherForecast>? ListRowTemplate { get; set; }
[Parameter] public RenderFragment<WeatherForecast>? HeaderTemplate { get; set; }
private RenderFragment Rows => (builder) =>
{
if (this.ListRowTemplate is null)
return;
builder.OpenElement(0, "tdbody");
foreach (var forecast in ForecastList)
builder.AddContent(2, this.ListRowTemplate(forecast));
builder.CloseElement();
};
}

供参考FetchData如下所示:

@page "/fetchdata"
<PageTitle>Weather forecast</PageTitle>
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from a service.</p>
<ListOfWeather ForecastList="this.Forecasts">
<HeaderTemplate>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</HeaderTemplate>
<ListRowTemplate>
<tr>
<td>@context.Date.ToShortDateString()</td>
<td>@context.TemperatureC</td>
<td>@context.TemperatureF</td>
<td>@context.Summary</td>
<td></td>
</tr>
</ListRowTemplate>
</ListOfWeather>
@code {
private List<WeatherForecast> Forecasts = new List<WeatherForecast>();
[Inject] private WeatherForecastService? service { get; set; }
private WeatherForecastService Service => service!;
protected override async Task OnInitializedAsync()
{
this.Forecasts = await Service.GetForecastAsync(DateTime.Now);
}
}

相关内容

  • 没有找到相关文章

最新更新