Рендеринг объектов C # в HTML - PullRequest
7 голосов
/ 26 мая 2009

У нас есть набор доменных сущностей, которые должны быть отображены в формате html, который показывает их детали во всплывающем окне.

Я был бы рад сделать что-то вроде этого:

Product product = new Product(...);
product.ToHtml();  // or: HtmlRenderer.Render(Product);

но моя главная проблема в том, как сделать это сзади. У меня есть 3 разных ответа:

1. Визуализация по коду:

Я могу просто написать свой код для рендеринга Html внутри метода ToHtml (C #) - проблема в том, что он слишком статический. если вы хотите немного переместить заголовок в середину, вы должны изменить код. кроме того, очень трудно прочитать отступ HTML в C #.

2. Использование XSL:

XSL-файлы могут легко управлять Html-шаблоном, и с помощью XSLT я могу преобразовать XML-файл в нужное место документов. парсер уже написан кем-то другим (просто нужно изучить синтаксис) ** для этого нам потребуется, чтобы каждый объект мог сериализоваться в Xml. и если объект изменился -> XML будет изменен -> xslt тоже нужно изменить ** это также даст мне возможность легко сделать отступ в HTML, например: добавить возможности CSS и \ или изменить дизайн HTML

3. используя другой шаблонизатор:

Напишите мой собственный шаблонный движок C # -> Html, чтобы он считывал шаблон из файла (* .template) и вставлял правильное свойство в нужное место шаблона с помощью отражения. ** в этом решении у нас есть много вопросов, о которых мы можем подумать, например: каким должен быть синтаксис? это хорошо? % Имя% % Описание% и как мы можем обращаться с массивами? ** Может быть, мы можем использовать существующий двигатель (Brail или T4-Templating)?

Что вы предпочитаете? ты знаешь хороший двигатель? сейчас я предпочитаю второе решение, но оно будет очень медленным.

спасибо

Ответы [ 7 ]

5 голосов
/ 26 мая 2009

У меня когда-то была необходимость отрисовать коллекцию любого типа в HTML-таблицу. Я создал метод расширения для IEnumerable , который имел перегрузки для CSS и тому подобное. Вы можете увидеть мой пост в блоге об этом здесь:

http://crazorsharp.blogspot.com/2009/03/cool-ienumberable-extension-method_25.html

Он использует отражение, чтобы получить все свойства объекта, и визуализирует симпатичный столик. Посмотрим, сработает ли это для вас.

[System.Runtime.CompilerServices.Extension()]
public string ToHtmlTable<T>(IEnumerable<T> list, string propertiesToIncludeAsColumns = "")
{
    return ToHtmlTable(list, string.Empty, string.Empty, string.Empty, string.Empty, propertiesToIncludeAsColumns);
}

[System.Runtime.CompilerServices.Extension()]
public string ToHtmlTable<T>(IEnumerable<T> list, string tableSyle, string headerStyle, string rowStyle, string alternateRowStyle, string propertiesToIncludeAsColumns = "")
{
    dynamic result = new StringBuilder();
    if (String.IsNullOrEmpty(tableSyle)) {
        result.Append("<table id=\"" + typeof(T).Name + "Table\">");
    } else {
        result.Append((Convert.ToString("<table id=\"" + typeof(T).Name + "Table\" class=\"") + tableSyle) + "\">");
    }

    dynamic propertyArray = typeof(T).GetProperties();

    foreach (object prop in propertyArray) {
       if (string.IsNullOrEmpty(propertiesToIncludeAsColumns) || propertiesToIncludeAsColumns.Contains(prop.Name + ",")) {
        if (String.IsNullOrEmpty(headerStyle)) {
            result.AppendFormat("<th>{0}</th>", prop.Name);
        } else {
            result.AppendFormat("<th class=\"{0}\">{1}</th>", headerStyle, prop.Name);
        }
      }
    }

    for (int i = 0; i <= list.Count() - 1; i++) {
        if (!String.IsNullOrEmpty(rowStyle) && !String.IsNullOrEmpty(alternateRowStyle)) {
            result.AppendFormat("<tr class=\"{0}\">", i % 2 == 0 ? rowStyle : alternateRowStyle);

        } else {
            result.AppendFormat("<tr>");
        }
        foreach (object prop in propertyArray) {
            if (string.IsNullOrEmpty(propertiesToIncludeAsColumns) || propertiesToIncludeAsColumns.Contains(prop.Name + ",")) {
                object value = prop.GetValue(list.ElementAt(i), null);
                result.AppendFormat("<td>{0}</td>", value ?? String.Empty);
            }
        }
        result.AppendLine("</tr>");
    }

    result.Append("</table>");

    return result.ToString();
}
3 голосов
/ 26 мая 2009

Я не могу больше согласиться с Джоном Феминеллой. Интеграция рендеринга Html непосредственно в ваши доменные объекты - это ужасное загрязнение вашего домена с совершенно произвольной и внешней проблемой. Как сказал Джон, вы сделаете свои сущности очень хрупкими, сделав это, и нарушите оба этих критических правила: разделение интересов и единую ответственность.

Из вашего выбора # 3 является наиболее близким к подходящему способу сделать это. Вам не нужно писать свой собственный шаблонизатор. В сети имеется множество бесплатных и готовых шаблонизаторов, которые выполнят эту работу более чем адекватно (NVelocity, StringTemplate, Brail и т. Д. И т. Д.)

Сохраняйте рендеринг в том месте, где он принадлежит ... в вашей презентации / просмотре, и не загрязняйте свой домен проблемами более высокого уровня.

3 голосов
/ 26 мая 2009

Это работа вашего взгляда, а не ваших контроллеров или моделей. Как вы подозреваете, использование метода (1) сделает ваши изменения очень хрупкими. Вместо этого напишите фрагмент представления для каждого способа, которым вы хотите отобразить конкретную сущность домена. Затем просто откройте соответствующие представления, чтобы создать окончательную страницу.

2 голосов
/ 26 мая 2009

Я искренне предпочитаю метод A. HTML уже является стандартом, поэтому не стоит слишком сильно себя мучить с помощью промежуточных форматов, таких как XML (через XSL - метод 2) или пользовательский формат (метод 3).

Если вы пишете в / для ASP.NET MVC, вы можете построить .ASCX (пользовательский элемент управления), который будет принимать объект вашего типа и отображать соответствующий HTML. И вы не получите неприятного C # отступа, а также выделения или автозаполнения.

Вы также можете написать несколько пользовательских представлений для размещения различных сценариев для одного типа объекта.

1 голос
/ 03 марта 2014

После небольшого исследования я сделал свою собственную функцию для преобразования любого объекта в HTMLString.

VB .Net код:

 Public Function ToHtmlString(ByVal fObj As Object) As String
    Dim pType = fObj.GetType()
    Dim props As IList(Of PropertyInfo) = pType.GetProperties()
    Dim value As Object = Nothing
    Dim htmlString As String = "<html><body><form>"

    For Each p In props
        value = p.GetValue(fObj, Nothing)
        If value <> Nothing Then
            htmlString += String.Format("<input type=""hidden"" name=""{0}"" id=""{0}"" value=""{1}""/>", p.Name, value)
        End If
    Next

    htmlString += "</form></body></html>"
    Return htmlString.ToString()

он получит имя свойства и значение от конкретного объекта. Вы можете манипулировать HTML на основе вашего

0 голосов
/ 26 мая 2009

Лично я бы объединил второй и третий метод: просто создаю общий XML-документ, используя отражение, скажем:

<object type="xxxx">
    <property name="ttt" value="vvv"/>
    ...
</object>

и используйте таблицу стилей XSTL для создания фактического HTML-кода из этого.

0 голосов
/ 26 мая 2009

Существует ли причина, по которой вы не хотите создавать пользовательский управляющий файл .ascx, который принимает в качестве аргумента объектные сущности объекта, а затем вы можете создавать графический интерфейс любым удобным вам способом. Таким образом, вы можете динамически добавлять элементы управления на страницу и просто установить свойство для их заполнения.

Редактировать 1: Просто переведите элемент управления в HTMLTextWriter, а не размещайте его на странице.

        StringBuilder outString = new StringBuilder();
        StringWriter outWriter = new StringWriter(outString);
        HtmlTextWriter htmlText = new HtmlTextWriter(outWriter);
        System.Web.UI.WebControls.Label lbl1 = new System.Web.UI.WebControls.Label();
        lbl1.Text = "This is just a test!";
        lbl1.ToolTip = "Really";
        lbl1.RenderControl(htmlText);
        ViewData["Output"] = outString.ToString();

выход

<span title="Really">This is just a test!</span>

Конечно, используйте встроенный элемент управления вместо встроенного, но это была быстрая и простая демонстрация.

...