6

我无法让 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 之后的文本块不会与前一个块在同一行开始,即使它会换行到下一行。

我希望每个文本块从前一个文本块的结尾处开始,在同一行。我想在某些文本上放置单击事件处理程序。我也想要分段。本质上,我正在尝试解决 Silverlight 2.0 的 XAML 子集中缺少 FlowDocument 和 Hyperlink 控件的问题。


要回答答案中提出的问题:

为什么不对不可点击的文本使用运行?如果我只在可点击的文本上使用单独的 TextBlocks,那么这些文本位仍然会受到上述换行问题的影响。链接之前的 TextBlock 和之后的 TextBlock。基本上都是。看起来我没有很多机会在同一个 TextBlock 中进行多次运行。

用正则表达式和循环将链接与其他文本分开根本不是问题,问题在于显示布局。

为什么不将每个单词放在 WrapPanel 中的单个 TextBlock 中除了是一个丑陋的 hack 之外,这与换行符根本不兼容 - 布局不正确。

它还会使链接文本的下划线样式变为虚线。

这是一个示例,每个单词都在其自己的 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 的点击并确定单击了哪个运行 运行没有鼠标事件,但包含 TextBlock 有。我找不到检查跑步是否在鼠标下方(Silverlight 中不存在 IsMouseOver)或查找跑步的边界几何(无剪辑属性)的方法。

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);
4

9 回答 9

29

为什么不能使用跑步?

使用运行来连接所有不会有事件的值,然后那些有事件的值会分解到他们自己的文本块中,冲洗泡沫重复。

在我看来,您应该能够使用 RegEx 和一些循环来做到这一点。查看 Jesse Liberty 在 wrap panel 上的帖子,看看这是否会激发任何想法。 http://silverlight.net/blogs/jesseliberty/archive/2008/12/03/the-wrap-panel.aspx

hth

于 2008-12-04T23:28:54.200 回答
2

I'm going to put in some answers to my own question, based on what I have found:

1) you can do this easily in the full-fat desktop WPF with a flow document full of paragraph, hyperlink, run and related objects.

This is what I am doing now, I am not trying to solve this problem in Silverlight any more.

2) Use Silverlight 4 You can't do this in Silverlight 2 or 3. However Silverlight 4 has a RichTextArea Control which, when readonly, supports this kind of display of flow layout with inline hyperlinks, and so acts like a cut-down version of FlowDocument and related classes from WPF. Silverlight 4 also allows Embedded Web browser control to display HTML content, if you can make it look that same across Windows versions (i.e. IE versions) and on Mac and potentially other platforms.

3) You can probably do something like this in Silverlight (any version) by building up a string of HTML and injecting it into the DOM to show it in the part of the page that's outside the Silverlight control. It sounds entirely workable, but in my opinion, too clever by half.

于 2009-02-02T12:27:54.347 回答
0

这行得通吗? http://www.silverlightshow.net/items/Silverlight-LinkLabel-control.aspx

于 2008-12-10T16:49:12.740 回答
0

您可以尝试在 TextBlock 内使用 ONLY Runs,并对整个 TextBlock 使用单击处理程序。然后,处理程序可以使用 click 事件的坐标定位源 Run,找出它是否是一个链接(作为链接的每个 Run 可以有一个特定的 x:Name,或者您甚至可以派生自己的 Run)并调用正确的功能那个链接。

我从未尝试过,但这是我尝试解决问题的方式。

于 2008-12-05T13:50:36.393 回答
0

虽然没有 IsMouseOver 类型属性,但您可以查看使用 VisualTreeHelper.FindElementsInHostCoordinates()

于 2008-12-06T18:00:56.670 回答
0

我认为最好的方法是让每个单词成为一个文本块,然后将这些单词附加到特定部分所需的正确事件处理程序。这将为您提供所需的换行,并且对于第一个单词的缩进,您可以设置它的左边距。

有关使用文本和换行面板完成类似操作的示例,请参阅本文。 http://jesseliberty.com/2008/12/03/the-wrap-panel/

于 2008-12-05T18:12:49.173 回答
0

试试这个:http: //blogs.msdn.com/delay/archive/2007/09/10/bringing-a-bit-of-html-to-silverlight-htmltextblock-makes-rich-text-display-easy.aspx

Silverlight 的 HtmlTextBlock。这并不是一个真正完成的概念,但它可能是一个很好的起点。

于 2008-12-11T00:02:24.690 回答
0

一个非常有趣的问题。您可能需要创建自己的自定义控件来处理这种类型的布局。您可以使用 Runs,但在每次运行的顶部覆盖一个透明画布,以便您可以处理与该运行相关的点击事件。根本不是一个简单的解决方案,但我认为这是可能的。

请让我知道你带来了什么。

于 2008-12-03T18:32:58.183 回答
0

我不确定您是否正在检查您的评论中的评论,因为您没有解决我在您的评论中所说的一些事情。使用 VisualTreeHelper.FindElementsInHostCoordinates() 找不到运行的原因是它只返回 UIElement,而运行不是 UIElement。如果您将此方法与不使用任何运行的建议相结合,那么您应该没问题吧?

作为文本块的每个单词都不是真正的“hack”,您可以通过将换行符分隔到它们自己的文本块中并为这些文本块分配等于宽度的宽度或边距来解决换行符的问题包裹面板,这将迫使他们坐在自己的线上。绝对不是最理想的解决方案,但我还没有看到任何其他显示任何承诺的东西。

于 2008-12-08T14:32:36.840 回答