如何简化此MVC Razor列表渲染器?

时间:2015-03-03 15:55:44

标签: c# .net asp.net-mvc razor

我目前正在使用多种生成小块和大块HTML的方法,详见答案: Helper methods to generate small HTML snippets

我还可以添加一个额外的东西 - 我也使用优秀的"使用模式"创建我自己的HTML容器类,即

using Html.BeginWidget("title")
{
    // Add things inside widget.
}

到目前为止,这已经证明非常便于使视图易于阅读和维护。这很重要,因为这项工作的一部分是允许设计人员和其他技术非开发人员创建和维护他们自己的视图,或者通过使这些视图足够简单,或者通过使用服务器端工具来生成"默认"表格观点。

为了达到这一点,我目前正在尝试标准化列表的呈现,并封装所有排序,过滤和搜索背后的所有代码。每个视图上都可以有多个这样的列表,因此很快就会失控。

我的想法是使用"使用模式"创建列表容器,然后是"枚举器模式"提供对每个项目的引用返回视图,如下:

    using (HtmlList<Location> list = Html.BeginList(locations))
    {
        while (list.MoveNext())
        {
            @(list.Current.Item.Name)
        }
    }

在辅助函数上有一些通用约束,所以它只接受实现它需要工作的接口的模型。

这很有效,但是存在一个大问题 - 我需要能够控制链接本身的某些属性,同时自动生成其他属性。单独的Enumerator模式意味着在我获得项目引用时已经创建了链接。

为了解决这个问题,我采用了枚举器并在列表中串联使用模式:

    using (HtmlList<Location> list = Html.BeginList(locations))
    {
        while (list.MoveNext())
        {
            list.Current.Url = Url.Action("A", "C", new { id = list.Current.Item.ID });

            using (list.RenderCurrent())
            {
                <img src="/Images/Icons/25/@(list.Current.Item.Icon).png" />
                @(list.Current.Item.Name) <i>(@(list.Current.Item.Type))</i>
                <p>@(list.Current.Item.ShortDescription)</p>
            }
        }
    }

我将这个项目包装在一个HtmlListItem类中,它给了我这里需要的属性。这使我可以在呈现之前访问该项目。

但是,对于一些设计师而言,这开始变得有点过于复杂了。

有人可以考虑采用不同的方法或任何建议来简化这种使用模式吗?


减少上一个例子中使用的类的版本:

HtmlList.cs

public class HtmlList<T> : IDisposable
{
    private HtmlListItem current;
    private IEnumerator<T> enumerator;
    private HtmlHelper html;
    private IEnumerable<T> items;
    private StringBuilder stringBuilder;

    protected internal HtmlList(HtmlHelper html)
    {
        this.html = html;
    }

    public HtmlListItem Current { get { return this.current; } }

    public IEnumerable<T> Items
    {
        get { return this.items; }
        protected internal set
        {
            this.items = value;
            this.enumerator = this.items.GetEnumerator();
        }
    }

    public void Dispose()
    {
        this.EndRender();
    }

    public bool MoveNext()
    {
        if (this.enumerator.MoveNext())
        {
            this.current = new HtmlListItem(html, this.enumerator.Current);
            return true;
        }

        this.current = HtmlListItem.None;
        return false;
    }

    public HtmlListItem RenderCurrent()
    {
        return this.current.BeginRender();
    }

    protected internal virtual HtmlList<T> BeginRender()
    {
        this.stringBuilder = new StringBuilder();

        this.stringBuilder.Append("<div class=\"list\">");

        this.html.ViewContext.Writer.Write(stringBuilder.ToString());
        this.stringBuilder = null;

        return this;
    }

    protected internal virtual void EndRender()
    {
        this.html.ViewContext.Writer.Write("</div>");
    }

    public class HtmlListItem : IDisposable
    {
        private static HtmlListItem none = null;
        private string cssClass = "";
        private HtmlHelper html;
        private T item;
        private StringBuilder stringBuilder;
        private string url = "";

        public HtmlListItem(HtmlHelper html, T item)
        {
            this.html = html;
            this.item = item;
        }

        public static HtmlListItem None { get { return HtmlListItem.none; } }

        public string CssClass { get { return this.cssClass; } set { this.cssClass = value; } }

        public T Item { get { return this.item; } }

        public string Url { get { return this.url; } set { this.url = value; } }

        public void Dispose()
        {
            this.EndRender();
        }

        protected internal virtual HtmlListItem BeginRender()
        {
            this.stringBuilder = new StringBuilder();

            this.stringBuilder.Append("<a");
            if (this.Url != "")
            {
                this.stringBuilder.Append(" href=\"" + this.Url + "\"");
            }
            if (this.CssClass != "")
            {
                this.stringBuilder.Append(" class=\"" + this.CssClass + "\"");
            }
            this.stringBuilder.Append(">");

            this.html.ViewContext.Writer.Write(stringBuilder.ToString());
            this.stringBuilder = null;

            return this;
        }

        protected internal virtual void EndRender()
        {
            this.html.ViewContext.Writer.Write("</a>");
        }
    }
}

HtmlListHelpers.cs

public static class HtmlListHelpers
{
    public static HtmlList<T> BeginList<T>(this HtmlHelper html, IEnumerable<T> listItems)
    {
        return new HtmlList<T>(html) { Items = listItems }.BeginRender();
    }
}

0 个答案:

没有答案