无法获得我想要的文本包装行为

时间:2008-12-02 20:13:58

标签: xaml silverlight text silverlight-2.0

我无法让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以后不会在前一个块的同一行开始,即使它会被包裹到以下几行。

我希望每个文本块在同一行上从前一个文本块结束。我想在某些文本上放置click事件处理程序。我还想要段落休息。基本上我正在努力解决Silverlight 2.0的XAML子集中缺少FlowDocument和Hyperlink控件的问题。


回答答案中提出的问题:

为什么不对不可点击的文本使用运行?如果我只对可点击的文本使用单独的TextBlocks,那么这些文本仍将受到上述包装问题的影响。而TextBlock就在链接之前,而TextBlock就在之后。基本上所有这一切。看起来我没有很多机会在同一个TextBlock中放置多个运行。

将链接与其他文本与RegExs和循环分开根本不是问题,问题是显示布局。

为什么不将每个单词放在WrapPanel中的单个TextBlock中除了作为一个丑陋的黑客之外,这对于换行没有好处 - 布局不正确。

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

这是一个示例,其中每个单词都在自己的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>

作为herehere的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;
}

使用带有空格的空文本块,将内容添加到后续行

我还在想这个。 如何计算换行块的正确宽度以强制将内容强制到下一行?太短,以下内容仍然在右边的同一行。太长,“linebreak”将在以下行,其后面的内容。调整控件大小时,您必须调整中断的大小。

有些代码是:

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

9 个答案:

答案 0 :(得分:29)

为什么你不能使用跑步?

使用运行来连接所有不会发生事件的值,然后将那些有事件的值分解为自己的文本块,然后再冲洗重复。

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

HTH

答案 1 :(得分:2)

根据我的发现,我将根据自己的问题提出一些答案:

1)您可以在全文桌面WPF中轻松完成此操作,其中包含完整的段落,超链接,运行和相关对象的流文档

这就是我现在正在做的事情,我不再试图在Silverlight中解决这个问题了。

2)使用Silverlight 4 您无法在Silverlight 2或3中执行此操作。但Silverlight 4有一个RichTextArea控件,当readonly支持这种带有内联超链接的流布局显示时,因此就像一个简化版的FlowDocument和来自WPF的相关类。 Silverlight 4还允许嵌入式Web浏览器控件显示HTML内容,如果您可以在Windows版本(即IE版本)以及Mac和其他可能的平台上使其看起来相同。

3)您可以通过构建一串 HTML并将其注入DOM 以在Silverlight控件之外的页面的一部分。这听起来完全可行,但在我看来,太聪明了一半。

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

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

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

答案 5 :(得分:0)

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

答案 6 :(得分:0)

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

作为一个文本块的每个单词并不是真正的“黑客”,你可以通过将换行符分隔成自己的文本块并为这些文本块分配宽度或边距等于包裹板的宽度会迫使它们坐在自己的线上。绝对不是最理想的解决方案,但我还没有看到任何其他任何有希望的东西。

答案 7 :(得分:0)

答案 8 :(得分: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。这不是一个真正的finsihed概念,但它可能是一个很好的起点。