Не могу получить поведение обтекания текстом, которое я хочу - PullRequest
6 голосов
/ 02 декабря 2008

У меня проблемы с тем, чтобы 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 в подмножестве Silverlight 2.0 XAML.


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

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

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

Почему бы не поместить каждое слово в отдельный текстовый блок в 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) или найти ограничивающую геометрию прогона (без свойства clip).

Существует 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);

Ответы [ 9 ]

29 голосов
/ 05 декабря 2008

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

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

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

НТН

2 голосов
/ 02 февраля 2009

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

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. Звучит вполне выполнимо, но, на мой взгляд, слишком умно наполовину.

0 голосов
/ 11 декабря 2008

Попробуйте это: 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. На самом деле это не законченная концепция, но она может стать хорошей отправной точкой.

0 голосов
/ 10 декабря 2008
0 голосов
/ 08 декабря 2008

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

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

0 голосов
/ 06 декабря 2008

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

0 голосов
/ 05 декабря 2008

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

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

0 голосов
/ 05 декабря 2008

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

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

0 голосов
/ 03 декабря 2008

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

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

...