Используя StringBuilder и DataTable, как мне вернуть несколько строк в трех столбцах без разрыва, когда есть только одна строка?

У меня есть функция, которая возвращает список адресов электронной почты из хранимого SQL Proc на основе вызываемого идентификатора. Он использует StringBuilder и возвращает один столбец. Для большинства идентификаторов есть 4 или менее адресов электронной почты, и этот формат подходит. Однако теперь мы получаем больше идентификаторов с более чем 10 адресами электронной почты, и это делает страницу слишком длинной.

Функция:

DataTable dt = DAL.ExecStoredProc(DAL.DatabaseName.DB, "storedProc", param);
StringBuilder sb = new StringBuilder();
sb.Append("<br/><br/>");
sb.Append("<table border='0' cellpadding='3'>");
for (int i = 0; i < dt.Rows.Count; i++)
{
    sb.Append("<tr><td>");
    sb.Append(dt.Rows[i]["EMail"].ToString());
    sb.Append("</td></tr>");
}
sb.Append("</table>");
return sb.ToString();

Я пытался использовать следующее, но оно ломается, когда слишком мало адресов для возврата:

DataTable dt = DAL.ExecStoredProc(DAL.DatabaseName.DB, "storedProc", param);
StringBuilder sb = new StringBuilder();
sb.Append("<br/><br/>");
sb.Append("<table border='0' cellpadding='3'>");
for (int i = 0; i < dt.Rows.Count; i++)
{
    sb.Append("<tr><td>");
    sb.Append(dt.Rows[i]["EMail"].ToString());
    i++;
    sb.Append("</td>");
    sb.Append("<td>");
    sb.Append(dt.Rows[i]["EMail"].ToString());
    i++;
    sb.Append("</td>");
    sb.Append("<td>");
    sb.Append(dt.Rows[i]["EMail"].ToString());
    i++;
    sb.Append("</td></tr>");
}
sb.Append("</table>");
return sb.ToString();

person InsertOldUserIDHere    schedule 21.09.2010    source источник
comment
Извините, что не добавил это сначала. Это сайт ASP.NET 2.0, и обновление версии в настоящее время невозможно.   -  person InsertOldUserIDHere    schedule 21.09.2010
comment
Не беспокойся. Я отредактировал свой ответ, чтобы использовать тернарный оператор, посмотрите, поможет ли это.   -  person Donut    schedule 21.09.2010


Ответы (3)


Используя функцию Linq Take, вы можете заменить следующий блок кода из ваш первый пример:

for (int i = 0; i < dt.Rows.Count; i++)
{
    sb.Append("<tr><td>");
    sb.Append(dt.Rows[i]["EMail"].ToString());
    sb.Append("</td></tr>");
}

с этим:

foreach (var row in dt.Rows.OfType<DataRow>().Take(3))
{
    sb.Append("<tr><td>");
    sb.Append(row["EMail"].ToString());
    sb.Append("</td></tr>");
}

Так как Take возвращает до указанного количества элементов с начала последовательности, этот блок кода будет выполняться от 0 до 3 раз. У вас будет отображаться максимум 3 адреса (даже если их больше), и вы не получите IndexOutOfRangeException, если у вас меньше 3.


ОБНОВЛЕНИЕ: совместимость с ASP.NET 2.0

Поскольку вы не можете использовать Linq, это должно иметь тот же результат:

for (int i = 0; i < (dt.Rows.Count > 3 ? 3 : dt.Rows.Count); i++)
{
    sb.Append("<tr><td>");
    sb.Append(dt.Rows[i]["EMail"].ToString());
    sb.Append("</td></tr>");
}

В выражении dt.Rows.Count > 3 ? 3 : dt.Rows.Count используется оператор ?. чтобы заставить цикл for повторяться по всем адресам электронной почты, если их не более 3, и в этом случае он будет повторяться только 3 раза.

person Donut    schedule 21.09.2010
comment
Мне это нравится, но, поскольку сайт .net 2.0, я не думаю, что LINQ подходит. Извините, но я не указал версию сначала. - person InsertOldUserIDHere; 21.09.2010
comment
При компиляции for возвращает оператор '›' не может быть применен к операндам типа 'bool' и 'int' - person InsertOldUserIDHere; 21.09.2010
comment
Извините за это, должны были быть скобки. Используйте (dt.Rows.Count > 3 ? 3 : dt.Rows.Count), см. мое редактирование. - person Donut; 21.09.2010
comment
Это привело меня к тому, что я искал, и ответило на мой вопрос. Однако сообщение Дуга ниже заставило меня задуматься о повторителях. Это привело к списку данных, и в итоге я заменил его на список данных. Еще раз спасибо, так как это было очень полезно узнать. - person InsertOldUserIDHere; 22.09.2010

Вместо создания html-таблицы с помощью построителя строк вы рассматривали возможность использования управление повторителем asp.net. Вы можете привязать DataTable непосредственно к ретранслятору, а затем управлять html из области дизайна html. Это окажется гораздо более гибким для того, что вы пытаетесь сделать. Предполагается, что вы используете asp.net.

Также см. мой пост о создании пользовательского элемента управления asp.net, так как это даст вам максимальную гибкость, а также инкапсулирует вашу пользовательскую логику HTML.

Наслаждаться!

person Doug    schedule 21.09.2010
comment
Проблема, с которой я столкнулся при управлении повторителем, заключается в том, что я могу вернуть все результаты в один столбец, но не распределить их по трем. Следующее дает три столбца с одинаковыми результатами, а один ‹td› просто дает один столбец ‹ItemTemplate›‹tr› ‹td› ‹%# Eval(Email) %› ‹/td› ‹td› ‹%# Eval(Email ) %› ‹/td› ‹td› ‹%# Eval(Email) %› ‹/td› ‹/tr› ‹/ItemTemplate› - person InsertOldUserIDHere; 21.09.2010
comment
@zk - я вижу вашу проблему - лучшим выбором может быть создание быстрого пользовательского элемента управления, который даст вам именно тот результат, который вам нужен. Смотрите ссылку, которую я добавил в свой пост. - person Doug; 21.09.2010
comment
Это заставило меня задуматься об управлении списком данных, и после некоторого прочтения я обнаружил, что это отлично работает для меня. Так что, хотя это не был прямой ответ, я поднял его, чтобы заставить себя думать :) Большое спасибо, - person InsertOldUserIDHere; 22.09.2010
comment
@zk - рад, что это обсуждение привело вас к решению - person Doug; 22.09.2010

Я думаю Doug на правильном пути, но если вы настаиваете на том, чтобы сделать это с помощью StringBuilder и цикла for, попробуйте следующее:

DataTable dt = DAL.ExecStoredProc(DAL.DatabaseName.DB, "storedProc", param);

StringBuilder sb = new StringBuilder();
sb.Append("<br/><br/>");
sb.Append("<table border='0' cellpadding='3'>");

string rowFormat = "<tr><td>{0}</td><td>{1}</td><td>{2}</td></tr>";

for (int i = 0; i < dt.Rows.Count; i+=3)
{
    string[] rowEmails = { String.Empty, String.Empty, String.Empty };

    for (int j = 0; j < 3; j++)
    {
        if (i+j < dt.Rows.Count) rowEmails[j] = dt.Rows[i+j]["Email"].ToString();
    }

    sb.AppendFormat(rowFormat, rowEmails[0], rowEmails[1], rowEmails[2]);
}

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

return sb.ToString();
person Forgotten Semicolon    schedule 21.09.2010