Программное определение максимального размера текстового поля (WP7)

В настоящее время я пишу программу для чтения электронных книг для Windows Phone Seven и пытаюсь оформить ее как программу для чтения Kindle. Для этого мне нужно разделить мои книги на страницы, и это станет намного сложнее, когда добавятся переменные размеры шрифта.

Для этого на данный момент я просто добавляю слово за раз в текстовый блок, пока оно не станет выше своего контейнера. Однако, как вы можете себе представить, для документа объемом более 120 000 слов это занимает неприемлемое время.

Есть ли способ узнать, когда текст превысит границы (логически разделив его на страницы), без необходимости его фактического рендеринга? Таким образом, я смогу запустить его в фоновом потоке, чтобы пользователь мог тем временем продолжать чтение.

Пока единственная идея, которая пришла мне в голову, — выяснить, как текстовый блок определяет свои границы (в вызове меры?), но я понятия не имею, как найти этот код, потому что рефлектор ничего не показал.

Заранее спасибо!


person Liam Dawson    schedule 27.02.2011    source источник


Ответы (4)


Я делаю что-то подобное, чтобы настроить размер шрифта для отдельных текстовых полей (чтобы убедиться, что они все подходят). По сути, я создаю TextBlock в коде, устанавливаю все свои свойства и проверяю свойства ActualWidth и ActualHeight. Вот некоторый псевдокод, который поможет решить вашу проблему:

public static String PageText(TextBlock txtPage, String BookText)
{
    TextBlock t = new TextBlock();
    t.FontFamily = txtPage.FontFamily;
    t.FontStyle = txtPage.FontStyle;
    t.FontWeight = txtPage.FontWeight;
    t.FontSize = txtPage.FontSize;
    t.Text = BookText;

    Size Actual = new Size();
    Actual.Width = t.ActualWidth;
    Actual.Height = t.ActualHeight;

    if(Actual.Height <= txtPage.ActualHeight)
        return BookText;

    Double hRatio = txtPage.ActualHeight / Actual.Height;
    return s.Substring((int)((s.Length - 1) * hRatio));
}

Приведенный выше код является непроверенным, но, надеюсь, поможет вам начать работу. По сути, он видит, может ли текст поместиться в поле, если да, то все готово. Если нет, он выясняет, какой процент текста может поместиться, и возвращает его. Это не учитывает разрывы слов и может не быть идеальным совпадением, но должно вас приблизить.

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

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


Другой вариант - заранее рассчитать размер страницы для каждого потенциального размера шрифта (и жестко запрограммировать его с помощью оператора switch). Это может легко сойти с ума, если вы разрешаете любой шрифт и любую комбинацию размеров, и было бы ужасно, если бы вы разрешали смешанные шрифты/размеры, но работало бы очень хорошо. Скорее всего, у вас есть определенный диапазон читаемых размеров и всего несколько шрифтов. Создать тестовое приложение для расчета длины текста на странице для каждой из этих комбинаций было бы не так сложно и, вероятно, облегчило бы вашу жизнь, даже если программисту это не кажется правильным :)

person theChrisKent    schedule 01.03.2011
comment
Отмечено как ответ, потому что это лучший ответ на мой вопрос здесь. Хотя, возможно, это не тот маршрут, которым я пользуюсь. - person Liam Dawson; 07.04.2011

Из того, что я вижу, приложение Kindle использует алгоритм, аналогичный тому, который вы предлагаете. Обратите внимание, что:

  • обычно он показывает позицию в процентах по книге, но не показывает общее количество страниц.

  • если вы измените размер шрифта, то первое слово на странице останется прежним (вот откуда берется % ) - поэтому приложение Kindle просто выполняет переназначение на одну страницу, предполагая, что первое слово страницы остается прежним.

  • если вы измените размер шрифта, а затем прокрутите обратно до первой страницы, то на самом деле есть разрыв - они снова тянут содержимое вперед, чтобы заполнить первую страницу.

Исходя из этого, я бы посоветовал вам не индексировать всю книгу. Вместо этого просто сосредоточьтесь на текущей странице на основе какой-либо «позиции» (например, количество символов — отображается в процентах). Если вам нужно что-то сделать в фоновом потоке, просто посмотрите на следующую страницу (и, возможно, на предыдущую страницу), чтобы прокрутка могла быть более отзывчивой.

Кроме того, чтобы оптимизировать ваш опыт, вы можете внести несколько изменений в свой текущий алгоритм, которые вы можете попробовать:

  • попробуйте другую начальную точку и шаг поиска для вашего алгоритма - не нужно начинать с одного слова, а затем добавлять только одно слово за раз.

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

Кроме того, я также очень хотел бы попробовать использовать блоки <Run> в вашем TextBlock - возможно, получится получить относительное положение каждого Run в TextBlock - хотя мне еще не удалось этого сделать.

person Stuart    schedule 27.02.2011
comment
Хм. Я полагаю, что, вероятно, поэтому вы не можете слишком быстро прокрутить пару страниц подряд. Я подумаю об этом, но я все еще удивлен, что, похоже, нет способа разумно выполнить ручное «измерение». - person Liam Dawson; 28.02.2011
comment
+1, как вы описали, устройство Kindle тоже работает. И предложения, которые вы сделали, - единственные, которые я мог сделать (также пишу для чтения wp7 :)) - страница за страницей с использованием TextBlock в коде. - person jumbo; 11.03.2011

Я не нашел ссылки на этот пример от Microsoft под названием «Принципы нумерации страниц».

У него есть интересный пример кода, работающий в Windows Phone.

http://msdn.microsoft.com/en-us/magazine/hh205757.aspx

Вы также можете посмотреть эту статью о переходах страниц в Windows Phone и другие о последних штрихах проекта электронной книги.

Код можно загрузить: http://archive.msdn.microsoft.com/mag201111UIFrontiers/Release/ProjectReleases.aspx?ReleaseId=5776

person ppaulojr    schedule 08.09.2013

Вы можете запросить класс FormattedText, который используется AFAIK внутри textBlock. поскольку этот класс используется для форматирования текста при подготовке к рендерингу, это самый низкоуровневый доступный класс, и он должен быть быстрым.

person Elad Katz    schedule 27.02.2011
comment
К сожалению, это только конструкция WPF. - person Liam Dawson; 27.02.2011