Как бороться с ошибкой HTML-таблицы IE9, когда в некоторых строках отображается частичный столбец с частичным представлением?

Я вижу, что этот вопрос уже задавался вокруг IE9, но который добавляет дополнительные столбцы в случайных строках HTML-таблицы. Корень проблемы, кажется, ошибка IE 9, которая исправлена ​​в IE 10 (но у меня много пользователей IE9)

В нем говорится, что обычно это происходит с таблицами, построенными с помощью AJAX, но я вижу это на обычных страницах, которые выводят таблицы HTML.

Существует обходное решение для Javascript, но ответ предполагает, что вы строили таблицу с помощью Javascript (из вызова ajax). Я использую частичное представление (или в некоторых случаях просто визуализирую обычную отформатированную таблицу html непосредственно на одной странице), поэтому я хотел выяснить, есть ли решение для предотвращения этой проблемы пользовательского интерфейса в IE9, когда вы просто отображаете прямой HTML на стр.

Я хочу избежать буквального отсутствия пробелов в моем собственном коде, так как это будет очень сложно поддерживать.

3 ответа

Решение

Это возможно. Для частичных представлений это проще, потому что вы можете захватить вывод Html.Partial непосредственно, изменяя его перед записью ответа в выходной поток.

Чтобы сделать это, вы должны создать метод расширения, который может выглядеть примерно так:

public static class HtmlExtensions
{
    public static HtmlString PartialIE9TableFix(this HtmlHelper helper,
        string view, object model = null)
    {
        var partialOutput = helper.Partial(view, model).ToString();
        partialOutput = Regex.Replace(partialOutput, @"/td>\s+<td",
                            "/td><td", RegexOptions.IgnoreCase);

        return MvcHtmlString.Create(partialOutput);
    }
}

Как вы можете видеть, он захватывает вывод Html.Partial непосредственно, а затем выполнить замену на этом. Вы бы использовали это, по вашему мнению, так:

@Html.PartialIE9TableFix("YourPartial")

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

IE9TableFixFilter ниже очень сильно основан на коде из Minify HTML с.NET MVC ActionFilter.

using System;
using System.IO;
using System.Text;

public class IE9TableFixFilter : Stream
{
    public IE9TableFixFilter(Stream response, Func<string, string> filter)
    {
        this.response = response;
        this.filter = filter;
    }

    public override bool CanRead { get { return true; } }
    public override bool CanSeek { get { return true; } }
    public override bool CanWrite { get { return true; } }
    public override void Flush() { response.Flush(); }
    public override long Length { get { return 0; } }
    public override long Position { get; set; }

    public override int Read(byte[] buffer, int offset, int count)
    {
        return response.Read(buffer, offset, count);
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
        return response.Seek(offset, origin);
    }

    public override void SetLength(long value)
    {
        response.SetLength(value);
    }

    public override void Close()
    {
        response.Close();
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        //byte[] data = new byte[count];
        //Buffer.BlockCopy(buffer, offset, data, 0, count);
        string s = Encoding.Default.GetString(buffer);

        s = filter(s);

        byte[] outData = Encoding.Default.GetBytes(s);
        response.Write(outData, 0, outData.GetLength(0));
    }

    private Stream response;
    private Func<string, string> filter;
}

Большая часть кода здесь заполняет реализации для abstract Члены Stream, Важной частью является то, что происходит в Write метод.

Версия Write Из статьи сначала делаются копии байтов потока без фактического их использования. Там нет упоминания, если это по какой-то конкретной причине, но мне это кажется бесполезным, поэтому я прокомментировал эти строки.

Далее нам нужно создать простую ActionFilter применить фильтр ответов к:

using System.Text.RegularExpressions;
using System.Web.Mvc;

public class IE9TableFixFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var response = filterContext.HttpContext.Response;
        response.Filter = new IE9TableFixFilter(response.Filter,
            s => Regex.Replace(s, @"/td>\s+<td", "/td><td", RegexOptions.IgnoreCase));
    }
}

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

[IE9TableFixFilterAttribute]
public ActionResult Index()
{
    return View();
}

Обновить

Чтобы сделать атрибут фильтра более эффективным, вы можете просто применить его к браузерам, которые содержат строку user-agent MSIE 9.0:

public class IE9TableFixFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var request = filterContext.HttpContext.Request;
        var response = filterContext.HttpContext.Response;

        if (request.UserAgent.Contains("MSIE 9.0"))
        {
            response.Filter = new IE9TableFixFilter(response.Filter,
                s => Regex.Replace(s, @"/td>\s+<td", "/td><td", RegexOptions.IgnoreCase));
        }
    }
}

Я столкнулся с той же проблемой и оказался на этой странице в поисках решения. В моем случае проблема была в том, что HTML отображался с помощью элемента управления Repeater с ASP.Net 4.

Я проверил код, сгенерированный сервером с Чарльзом, и с HTML не было никаких проблем.

Последнее предложение в вопросе привело меня к моему собственному простому решению.

Я хочу избежать буквального отсутствия пробелов в моем собственном коде, так как это будет очень сложно поддерживать.

Я просто помещаю комментарии между открытием тега TR и первым тегом TD, а также между каждым TD и закрывающим тегом TR:

<tr><!--
 --><td class="cell">
    Cell 1  
    </td><!--
 --><td class="cell">
    Cell 2  
    </td><!--
 --><td class="cell">
    Cell 3  
    </td><!--
 --><td class="cell">
    Cell 1  
    </td><!--
 --></tr>

Это решение означает, что нам не нужно использовать расширение, и в будущем не составит труда прочитать или сохранить код.

Помимо очистки пробелов, вы можете попробовать одно из следующих исправлений:

  • CSS: td { white-space: nowrap; } если это применимо!

  • Заставьте ваши таблицы иметь фиксированную разметку:

<table style="table-layout: fixed" width="600">
  <colgroup>
    <col width="100"><col width="300"><col width="200">
  </colgroup>
  <tr height="20">
    <td>...</td>
    <td>...</td>
    <td>...</td>
  </tr>
</table>
  • Если ваше веб-приложение уже поддерживает IE8, вы можете заставить пользователей IE9 использовать механизм рендеринга IE8, используя:<meta http-equiv="X-UA-Compatible" content="IE=8" />
Другие вопросы по тегам