Sitecore FieldRenderer

发布时间 2023-11-10 17:15:12作者: 灵火

前提

Sitecore 的 @Html.Sitecore().Field("file icon", item, new {@class="icon", }) 确实也挺好用的,但是局限于 item ,当有多个 sub item,或者其他地方的 item,远不如使用 @Model 方便。

所以自己写了个 Helper:

public class CustomerRenderer : FieldRenderer
{
    private Stack<string> _endFieldStack;
    protected virtual Stack<string> EndFieldStack => this._endFieldStack ?? (this._endFieldStack = new Stack<string>());

    public CustomerRenderer(Item item, string fieldName)
    {
        base.Item = item;
        base.FieldName = fieldName;
    }

    private RenderFieldResult _result;

    public HtmlString BeginRender()
    {  
        _result = base.RenderField();
        string str = _result.ValueOrDefault<RenderFieldResult, string>(result => result.FirstPart).OrEmpty();
        this.EndFieldStack.Push(_result.ValueOrDefault<RenderFieldResult, string>(result => result.LastPart).OrEmpty());
        return new HtmlString(str);
    }

    public HtmlString EndRender()
    {
        Stack<string> endFieldStack = this.EndFieldStack;
        return endFieldStack.Count != 0 ? new HtmlString(endFieldStack.Pop()) : throw new InvalidOperationException("There was a call to EndField with no corresponding call to BeginField");
    }

    public HtmlString Wrap(Func<RenderFieldResult, string> wrap)
    {
        var final = new StringBuilder();
        var begin = BeginRender();
        var content = wrap(_result);
        var end = EndRender();
        final.Append(begin);
        final.Append(content);
        final.Append(end);
        return new HtmlString(final.ToString());
    }

    public override string ToString()
    {
        return this._result?.ToString();
    }
}

使用方法:

后台通过 Controller 将 Model 传到 View:

public class ArticleController : Controller{
    public ActionResult Index(){
        return View("~/Views/Article.cshtml", CreateModel());
    }

    public ArticleModel CreateModel(){
        var item = RenderingContext.Current.Rendering.Item;
        var articleModel = new ArticleModel()
        {
            FileTitle = new CustomerRenderer(item, "File Title"),
            FileIcon = new CustomerRenderer(item, "File Icon"),
            FileDescription = new CustomerRenderer(item, "File Description"),
        };
        return articleModel;
    }
    
    public class ArticleModel
    {
        public FieldRenderer FileTitle { get; set; }
        
        public FieldRenderer FileIcon { get; set; }
        
        public FieldRenderer FileDescription { get; set; }
    }
}
// ~/Views/Article.cshtml
// 用法一
@if (!string.IsNullOrEmpty(Model.FileDescription))
{
    <li>
        @Model.FileLink.BeginRender()
        <i class="icon">@Model.FileIcon</i>
        @Model.FileDescription
        @Model.FileLink.EndRender()
    </li>
}

// 用法二
@if (!string.IsNullOrEmpty(Model.FileDescription))
{
    <li>
        @Model.FileLink.Wrap(r => $"<i class=\"icon\">{Model.FileIcon}</i>{Model.FileDescription}")
    </li>
}

// 最后生成:
<li>
    <a><i class=""><img src="./icon" /></i>FileDescription</a>
</li>