我正在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>
类型吗?
[结束编辑]
几乎没有关于这项具体任务的信息。有人做过这样的事情吗?有什么建议吗?
我已经得出结论,你不能这么做。我添加了支持RenderFragment
和RenderFragment<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);
}
}