Silverlight 2.0 でテキストを思い通りにレイアウトするのに苦労しています。Web ページの 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 に各単語を配置しない理由はありません。見苦しいハックであることは別として、これは改行ではまったくうまく機能しません。レイアウトが正しくありません。
また、リンクされたテキストの下線スタイルを破線にします。
それぞれの単語が独自の 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>
hereとhereのような LinkLabelControl はどうですか。上記のアプローチとほとんど同じであるため、同じ問題があります。サンプルを実行してみて、リンク テキストが折り返されるまでどんどん長くしてください。リンクは新しい行で始まることに注意してください。リンク テキストをさらに長くして、リンク テキストが 1 行よりも長くなるようにします。まったくラップしないことに注意してください。このコントロールは、改行や段落の区切りも処理しません。
テキストをすべてランに入れて、含まれている TextBlock のクリックを検出し、どのランがクリックされたかを調べて みませんか? ランにはマウス イベントがありませんが、含まれている TextBlock にはあります。ランがマウスの下にあるかどうかを確認する方法 (Silverlight には IsMouseOver が存在しない) や、ランの境界ジオメトリを見つける方法 (クリップ プロパティがない) を見つける方法が見つかりません。
VisualTreeHelper.FindElementsInHostCoordinates()があります
以下のコードは、VisualTreeHelper.FindElementsInHostCoordinates を使用して、クリックでコントロールを取得します。Run は UiElement ではないため、出力には TextBlock がリストされますが、Run はリストされません。
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);