c# - 在 DotVVM 的自定义标记控件中呈现 ITemplate
问题描述
我正在尝试创建一个自定义控件,该控件呈现可以选择日期的日历。我需要能够将一个传递ITemplate
给每天都会呈现的控件。日子由中继器呈现。
由于目前没有允许绑定到一个ITemplate
(或将一个ITemplate
与集合以外的任何东西一起使用)的现有控件,我如何轻松地ITemplate
从一个呈现一个controlProperty
?我希望有某种只呈现的控件,ITemplate
以便它可以在其他地方重用。
部分控制标记:
<!-- ... -->
<dot:Repeater ID="DaysRepeater" DataSource="{value: Days}" class="list-group list-group-flush calendar-grid">
<ItemTemplate>
<div class="{{value: "calendar-day calendar-day-" + DayOfWeekIndex }}">
<dot:LinkButton ID="DayButton" class="{{value: "list-group-item list-group-item-action " + (Selected ? "active calendar-day-btn" : "calendar-day-btn") }}"
Click="{controlCommand: SelectDate(_this.Date)}">
{{value: DayText}}
<!-- RENDER TEMPLATE HERE -->
</dot:LinkButton>
</div>
</ItemTemplate>
</dot:Repeater>
代码隐藏中的 ItemTemplate:
[MarkupOptions(AllowBinding = false, MappingMode = MappingMode.InnerElement, Required = false)]
[ConstantDataContextChange(typeof(ICollection<CalendarDayModel>)), CollectionElementDataContextChange(1)]
public ITemplate ItemTemplate
{
get { return (ITemplate)GetValue(ItemTemplateProperty)!; }
set { SetValue(ItemTemplateProperty, value); }
}
public static readonly DotvvmProperty ItemTemplateProperty =
DotvvmProperty.Register<ITemplate, Calendar>(t => t.ItemTemplate);
控件的示例用法:
<cc:Calendar DataContext="{value: CalendarViewModel}" MultiSelect="true">
<ItemTemplate>
Selected: {{value: Selected}}
</ItemTemplate>
</cc:Calendar>
解决方案
不幸的是,我们在 DotVVM 中没有任何可以绑定模板并仅渲染它的控件。但是,您可以执行以下技巧:
- 使用
PlaceHolder
模板中的控件Repeater
:
<dot:Repeater ID="DaysRepeater" DataSource="{value: Days}" class="list-group list-group-flush calendar-grid">
<ItemTemplate>
<div class="{{value: "calendar-day calendar-day-" + DayOfWeekIndex}}">
<dot:LinkButton ID="DayButton" class="{{value: "list-group-item list-group-item-action " + (Selected ? "active calendar-day-btn" : "calendar-day-btn") }}"
Click="{controlCommand: SelectDate(_this.Date)}">
{{value: DayText}}
<dot:PlaceHolder ID="TemplateHost" />
</dot:LinkButton>
</div>
</ItemTemplate>
</dot:Repeater>
- 将
Repeater
模板替换为您自己的模板,该模板将首先渲染原始模板,然后找到占位符,并将内部模板放入其中:
protected override void OnInit(IDotvvmRequestContext context)
{
var repeater = (Repeater)FindControlInContainer("DaysRepeater");
repeater!.ItemTemplate = new TemplateWrapper(ItemTemplate, repeater!.ItemTemplate);
base.OnInit(context);
}
class TemplateWrapper : ITemplate
{
private readonly ITemplate innerTemplate;
private readonly ITemplate repeaterTemplate;
public TemplateWrapper(ITemplate innerTemplate, ITemplate repeaterTemplate)
{
this.innerTemplate = innerTemplate;
this.repeaterTemplate = repeaterTemplate;
}
public void BuildContent(IDotvvmRequestContext context, DotvvmControl container)
{
repeaterTemplate.BuildContent(context, container);
var placeholder = container.FindControlInContainer("TemplateHost");
innerTemplate.BuildContent(context, placeholder!);
}
}
推荐阅读
- android-studio - 链式方法调用:如果 long 会对具有许多参数的构造函数/函数造成奇怪的影响,请砍掉?
- laravel - 如何将包含大记录的 csv 文件上传到 Laravel 的数据库中
- c# - 为什么当我获取热门趋势时 TweetVolume 为空?
- java - 按下按钮时如何更改图像视图的图标?
- datetime - 在狮身人面像中索引日期时间
- javascript - Aurelia 选择禁用
- android - 当应用程序处于非活动状态时没有推送通知 PubNub
- java - 用户无法使用 selenium 发送文本以下拉
- android - 为什么 JobScheduler 在 Kotlin 中不起作用?
- python - 将 python 时间对象插入 MySQL 表