Программное определение максимального соответствия в текстовом поле (WP7) - PullRequest
5 голосов
/ 27 февраля 2011

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

Чтобы сделать это в данный момент, я просто добавляюСлово за раз в текстовый блок, пока он не станет выше, чем его контейнер.Как вы можете себе представить, с документом, содержащим более 120 000 слов, это занимает недопустимый период времени.

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

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

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

Ответы [ 4 ]

4 голосов
/ 27 февраля 2011

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

  • обычно показывает% позицию в книге - общее количество страниц не отображается.

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

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

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

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

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

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

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

3 голосов
/ 01 марта 2011

Я делаю что-то похожее, чтобы настроить размер шрифта для отдельных текстовых полей (чтобы они все подходили). По сути, я создаю 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));
}

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

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

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


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

1 голос
/ 09 сентября 2013

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

В Windows Phone есть несколько интересных примеров кода.

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

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

Код доступен для скачивания: http://archive.msdn.microsoft.com/mag201111UIFrontiers/Release/ProjectReleases.aspx?ReleaseId=5776

0 голосов
/ 27 февраля 2011

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

...