简体   繁体   中英

Rendering an ITemplate in custom markup control in DotVVM

I'm trying to create a custom control that renders a calendar in which days can be selected. I need the ability to pass an ITemplate to the control which will be rendered for each day. The days are rendered by a Repeater.

As there is currently no existing control that allows binding to an ITemplate (or use an ITemplate with anything other than a collection), how do I render an ITemplate from a controlProperty easily? I'd prefer to have some kind of control that just renders an ITemplate so it can be reused elsewhere.

Partial control markup:

    <!-- ... -->
    <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 in code-behind:

        [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);

Example usage of control:

<cc:Calendar DataContext="{value: CalendarViewModel}" MultiSelect="true">
    <ItemTemplate>
        Selected: {{value: Selected}}
    </ItemTemplate>
</cc:Calendar>

Unfortunately, we don't have any control in DotVVM that could bind a template and just render it. However, you can do the following trick:

  1. Use the PlaceHolder control in the template of the 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>
  1. Replace the Repeater template with your own one that will first render the original template, then find the placeholder, and puts the inner template inside:
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!);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM