Не могу получить желаемое поведение переноса текста

Мне не удается заставить Silverlight 2.0 размещать текст именно так, как я хочу. Мне нужен текст с разрывами строк и встроенными ссылками с переносом, как текст HTML на веб-странице.

Вот самое близкое, что я подошел:

<UserControl x:Class = "FlowPanelTest.Page"
    xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:Controls = "clr-namespace:Microsoft.Windows.Controls;assembly=Microsoft.Windows.Controls" 
    Width = "250" Height = "300">
    <Border BorderBrush = "Black" BorderThickness = "2" >
      <Controls:WrapPanel> 
      <TextBlock x:Name = "tb1" TextWrapping = "Wrap">Short text. </TextBlock>
      <TextBlock x:Name = "tb2" TextWrapping = "Wrap">A bit of text. </TextBlock>
      <TextBlock x:Name = "tb3" TextWrapping = "Wrap">About half of a line of text.</TextBlock>
      <TextBlock x:Name = "tb4" TextWrapping = "Wrap">More than half a line of longer text.</TextBlock>
      <TextBlock x:Name = "tb5" TextWrapping = "Wrap">More than one line of text, so it will wrap onto the  following line.</TextBlock>
      </Controls:WrapPanel>
      </Border>
</UserControl>

Но проблема в том, что хотя текстовые блоки tb1 и tb2 будут помещаться в одну строку, потому что для них достаточно места, tb3 и далее не будет начинаться с той же строки, что и предыдущий блок, даже если он будет переноситься на следующие строки.

Я хочу, чтобы каждый текстовый блок начинался там, где заканчивается предыдущий, на той же строке. Я хочу поместить обработчики событий щелчка в какой-то текст. Мне также нужны разрывы абзацев. По сути, я пытаюсь обойти отсутствие элементов управления FlowDocument и Hyperlink в подмножестве XAML Silverlight 2.0.


Чтобы ответить на вопросы, поставленные в ответах:

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

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

Почему бы не поместить каждое слово в отдельный TextBlock в WrapPanel Помимо того, что это уродливый хак, это совсем не работает с переносами строк - макет неправильный.

Это также сделало бы стиль подчеркивания связанного текста прерывистой линией.

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

<UserControl x:Class = "SilverlightApplication2.Page"
    xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" 
   xmlns:Controls = "clr-namespace:Microsoft.Windows.Controls;assembly=Microsoft.Windows.Controls" 
    Width = "300" Height = "300">
    <Controls:WrapPanel>
        <TextBlock  TextWrapping = "Wrap">Short1 </TextBlock>
        <TextBlock  TextWrapping = "Wrap">Longer1 </TextBlock>
        <TextBlock  TextWrapping = "Wrap">Longerest1 </TextBlock>
        <TextBlock  TextWrapping = "Wrap">
                <Run>Break</Run>
                <LineBreak></LineBreak>
        </TextBlock>
        <TextBlock  TextWrapping = "Wrap">Short2</TextBlock>
        <TextBlock  TextWrapping = "Wrap">Longer2</TextBlock>
        <TextBlock  TextWrapping = "Wrap">Longerest2</TextBlock>
        <TextBlock  TextWrapping = "Wrap">Short3</TextBlock>
        <TextBlock  TextWrapping = "Wrap">Longer3</TextBlock>
        <TextBlock  TextWrapping = "Wrap">Longerest3</TextBlock>
    </Controls:WrapPanel>
</UserControl>

А как насчет LinkLabelControl как здесь и здесь. У него те же проблемы, что и у описанного выше подхода, поскольку он почти такой же. Попробуйте запустить образец и сделайте текст ссылки длиннее и длиннее, пока он не завершится. Обратите внимание, что ссылка начинается с новой строки, чего не должно быть. Сделайте текст ссылки еще длиннее, чтобы текст ссылки был длиннее строки. Обратите внимание, что он совсем не заворачивается, а отрезается. Этот элемент управления также не обрабатывает разрывы строк и абзацев.

Почему бы не поместить весь текст в прогоны, обнаружить щелчки по содержащему его текстовому блоку и определить, какой прогон был нажат У прогонов нет событий мыши, но у содержащего их TextBlock есть. Я не могу найти способ проверить, находится ли пробег под мышкой (IsMouseOver отсутствует в Silverlight) или найти ограничивающую геометрию пробега (без свойства клипа).

Есть VisualTreeHelper.FindElementsInHostCoordinates ()

В приведенном ниже коде используется VisualTreeHelper.FindElementsInHostCoordinates для получения элементов управления одним щелчком мыши. В выходных данных указан TextBlock, но не Run, поскольку Run не является UiElement.

private void theText_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
    // get the elements under the click
    UIElement uiElementSender = sender as UIElement;
    Point clickPos = e.GetPosition(uiElementSender);
    var UiElementsUnderClick = VisualTreeHelper.FindElementsInHostCoordinates(clickPos, uiElementSender);

    // show the controls
    string outputText = "";
    foreach (var uiElement in UiElementsUnderClick)
    {
        outputText += uiElement.GetType().ToString() + "\n";
    }
    this.outText.Text = outputText;
}

Используйте пустой текстовый блок с полем для размещения следующего содержимого на следующей строке

Я все еще думаю об этом. Как рассчитать правильную ширину блока с разрывом строки, чтобы принудительно следовать содержимому на следующую строку? Слишком короткий, и следующий контент все равно будет на той же строке справа. Слишком длинный, и «разрыв строки» будет на следующей строке с содержимым после нее. Вам придется изменить размер разрывов при изменении размера элемента управления.

Вот часть кода для этого:

    TextBlock lineBreak = new TextBlock();
    lineBreak.TextWrapping = TextWrapping.Wrap;
    lineBreak.Text = " ";
    // need adaptive width 
    lineBreak.Margin = new Thickness(0, 0, 200, 0);

Можете ли вы опубликовать снимок экрана с эффектом, который пытаетесь получить? В xaml вверху нет ссылок, но вы продолжаете ссылаться на ссылки в своем вопросе.

Bryant 31.01.2009 02:35

Брайант: посмотрите любую веб-страницу.

Anthony 31.01.2009 23:48
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
6
2
5 305
9

Ответы 9

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

Пожалуйста, дайте мне знать, с чем вы пришли.

У меня плохое предчувствие по поводу фразы "интересный вопрос".

Anthony 04.12.2008 00:03

Почему вы не можете использовать пробежки?

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

Мне кажется, у вас должно получиться сделать это с помощью RegEx и некоторого цикла. Прочтите сообщение Джесси Либерти на панели обертки и посмотрите, вызывает ли это какие-либо мысли. http://silverlight.net/blogs/jesseliberty/archive/2008/12/03/the-wrap-panel.aspx

hth

Я обратился к этому в вопросе выше.

Anthony 06.12.2008 16:53

Вы можете попробовать использовать ТОЛЬКО прогоны внутри своего TextBlock и использовать обработчик одного щелчка для всего TextBlock. Затем обработчик может найти исходный Run, используя координаты события щелчка, выяснить, является ли это ссылкой (каждый Run, который является ссылкой, может иметь конкретное x: Name, или вы даже можете получить свой собственный Run) и вызвать нужную функциональность для эта ссылка.

Никогда не пробовал, но так я бы попробовал решить проблему.

Я пытаюсь это сделать, но как определить местонахождение пробега? У вас есть координаты события щелчка, но я не понимаю, как найти границы выполнения.

Anthony 06.12.2008 16:52

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

См. В этой статье пример, в котором нечто подобное делается с текстом и панелью переноса. http://jesseliberty.com/2008/12/03/the-wrap-panel/

Вы можете обойти эту проблему, разделив разрывы строк на текстовые блоки и установив либо левое / правое поле, либо ширину текстовых блоков разрыва строки равными ширине панели-оболочки. принуждение их быть на своей линии. Не идеально, но это лучшее, что вы можете сделать.

Tom 06.12.2008 20:51

Хотя нет свойства типа IsMouseOver, вы можете использовать VisualTreeHelper.FindElementsInHostCoordinates ()

Хорошая идея, я не знал об этой функции. Я обсуждал это выше.

Anthony 07.12.2008 21:15

Я не уверен, проверяете ли вы комментарии к своим комментариям или нет, потому что вы не обратились к некоторым вещам, которые я сказал в своих комментариях в ответ на ваши. Причина, по которой вы не можете найти запуски с помощью VisualTreeHelper.FindElementsInHostCoordinates (), заключается в том, что он возвращает только UIElements, а Runs не являются UIElements. Если вы объедините этот метод с предложением не использовать никаких прогонов, тогда все будет в порядке, верно?

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

У меня не было времени попробовать это - комментарии выше.

Anthony 09.12.2008 01:48

Это сработает? http://www.silverlightshow.net/items/Silverlight-LinkLabel-control.aspx

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

Anthony 11.12.2008 18:06

Кроме того, измените текст ссылки в этом примере на «ссылки с длинным текстом вообще не переносятся этим элементом управления». Ссылка теперь начинается с новой строки, хотя этого не должно быть. WrapPanel не может обойти эту проблему, кроме как разбить ссылку на отдельные слова. Что было бы плохо, если бы ссылка была подчеркнута.

Anthony 11.12.2008 18:17

Или измените ссылку на "[link = " silverlightshow.net "target = " _ blank "] быстрая коричневая лиса перепрыгнула через расслабленную собаку, быстрая коричневая собака перепрыгнула через ленивую собаку [/ link]" - кнопка ссылки вообще не может обернуться .

Anthony 11.12.2008 23:28

Попробуй это: http://blogs.msdn.com/delay/archive/2007/09/10/bringing-a-bit-of-html-to-silverlight-htmltextblock-makes-rich-text-display-easy.aspx

Блок HtmlTextBlock для Silverlight. Это не совсем доработанная концепция, но может быть хорошей отправной точкой.

это хороший контроль, и если бы ссылки были интерактивными, то это было бы именно то, что я хотел. Но он помещает весь текст в тиражи. И они не кликабельны. См. Комментарии в вопросе.

Anthony 11.12.2008 18:09

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

Anthony 02.02.2009 15:29

Я собираюсь дать несколько ответов на свой вопрос, основываясь на том, что я нашел:

1), вы можете легко сделать это в полнофункциональном рабочий стол WPF с потоковым документом, полном абзацев, гиперссылок, прогонов и связанных объектов.

Это то, что я делаю сейчас, я больше не пытаюсь решить эту проблему в Silverlight.

2) Используйте Silverlight 4 Вы не можете сделать это в Silverlight 2 или 3. Однако Silverlight 4 имеет элемент управления RichTextArea, который, когда он доступен только для чтения, поддерживает такой вид отображения макета потока со встроенными гиперссылками и поэтому действует как урезанная версия FlowDocument и связанных с ним классы из WPF. Silverlight 4 также позволяет встроенному элементу управления веб-браузером отображать HTML-контент, если вы можете сделать так, чтобы он выглядел одинаково в версиях Windows (то есть версиях IE), а также на Mac и, возможно, на других платформах.

3) Вы, вероятно, можете сделать что-то подобное в Silverlight (любой версии), создав строку HTML и внедрение его в DOM, чтобы показать ее в той части страницы, которая находится за пределами элемента управления Silverlight. Звучит вполне работоспособно, но, на мой взгляд, наполовину умно.

Другие вопросы по теме