感謝所有,你的答案讓我迅速地產生一個基本的WPF代碼示例:
<Window x:Class="TextFlow.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TextFlow"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525" Background="Black" Foreground="Gray">
<Window.Resources>
<ControlTemplate x:Key="NoPageControls" TargetType="{x:Type FlowDocumentPageViewer}">
<AdornerDecorator>
<DocumentPageView FlowDocumentPageViewer.IsMasterPage="True" />
</AdornerDecorator>
</ControlTemplate>
</Window.Resources>
<Grid>
<FlowDocumentPageViewer Template="{StaticResource NoPageControls}">
<FlowDocument ColumnWidth="200" FontFamily="Segoe UI" FontSize="10">
<Paragraph>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae purus pellentesque, ultricies magna a, egestas nisl. Quisque eu risus quis elit posuere imperdiet. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla sagittis, felis at luctus tempus, metus dolor ultricies mi, vitae aliquet justo libero non arcu. Suspendisse potenti. Maecenas luctus rutrum lorem non congue. Sed vitae blandit felis. Nullam eu leo non dui vulputate tincidunt id eu odio. Etiam risus velit, consequat vel tortor in, condimentum vestibulum est. Sed maximus elementum erat nec fermentum.
</Paragraph>
<Paragraph>
Donec nec ex dignissim, ornare arcu eu, fermentum ipsum. Cras ullamcorper blandit quam, in pulvinar justo sodales quis. Vivamus sed tincidunt augue, nec convallis lorem. Phasellus lobortis nibh sem, sit amet suscipit tellus dapibus at. Aliquam arcu tellus, aliquet at cursus sodales, ornare a sem. Morbi sollicitudin orci et hendrerit ullamcorper. In non faucibus risus. Morbi eget metus pharetra quam consequat pretium quis ac enim. Integer scelerisque elit malesuada pharetra condimentum. Aliquam erat volutpat. Ut at consectetur erat. Phasellus pulvinar consequat erat quis placerat. Cras tortor mi, tempor ultricies sodales at, faucibus quis lacus. Morbi semper vestibulum odio eget tempor. Praesent at mollis erat. Praesent sollicitudin nulla sit amet magna fermentum porta.
</Paragraph>
<Paragraph>
Proin tincidunt ex interdum, sodales leo non, fringilla tellus. Vestibulum eget posuere purus, et aliquam arcu. Sed ac dolor ullamcorper, rutrum sapien sit amet, convallis enim. Mauris a faucibus augue. Morbi porta nunc ac ligula suscipit consequat. Curabitur in interdum elit. Pellentesque tempor tempor tellus, ut bibendum elit consequat vitae. Fusce commodo ac nunc ut pretium. Vestibulum ut vulputate est. Nullam pharetra ornare elementum. Nullam eros nunc, tincidunt at porta sit amet, rutrum in mauris. Vivamus id ante sit amet velit pulvinar interdum. Cras efficitur egestas nunc id tempor. Vivamus eu enim vitae lorem molestie tincidunt nec et ex. Integer nec turpis nisi.
</Paragraph>
</FlowDocument>
</FlowDocumentPageViewer>
</Grid>
</Window>
是,一些手工加工仍是必要的,但它是非常好的,當我只是想以可讀的方式顯示一些本地化的描述。
可以很容易地添加一些自動裝置(如確定是否需要列或它們應該有多寬),但我會盡可能地簡化示例。必須應用控件模板才能隱藏頁面控件。如果文字較大並且不適合放在一個頁面中 - 您只需保留原始模板。
很抱歉無法在UWP中使用。是嗎?
所以,我們需要更深入。沒有UWP的幫助,沒問題,讓我們做一個控制,至少可以做什麼WPF控制,對吧?
事不宜遲 - ReadableBlock
控制:
using System.Collections.Generic;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Documents;
namespace ReadableBlockDemo.Controls {
public sealed class ReadableBlock : ContentControl {
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(ReadableBlock), null);
public static readonly DependencyProperty TextAlignmentProperty =
DependencyProperty.Register("TextAlignment", typeof(TextAlignment), typeof(ReadableBlock), new PropertyMetadata(TextAlignment.Left));
public static readonly DependencyProperty ColumnsProperty =
DependencyProperty.Register("Columns", typeof(int), typeof(ReadableBlock), new PropertyMetadata(1));
public static readonly DependencyProperty ColumnSpacingProperty =
DependencyProperty.Register("ColumnSpacing", typeof(double), typeof(ReadableBlock), new PropertyMetadata(10d));
public string Text {
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public TextAlignment TextAlignment {
get { return (TextAlignment)GetValue(TextAlignmentProperty); }
set { SetValue(TextAlignmentProperty, value); }
}
public int Columns {
get { return (int)GetValue(ColumnsProperty); }
set { SetValue(ColumnsProperty, (int)value); }
}
public double ColumnSpacing {
get { return (double)GetValue(ColumnSpacingProperty); }
set { SetValue(ColumnSpacingProperty, (double)value); }
}
public new string Content {
get { return (string)GetValue(ContentProperty); }
set { base.Content = null; SetValue(ContentProperty, Text = (string)value); RenderText(); }
}
private StackPanel Container => base.Content as StackPanel;
private double AvailableWidth;
private double AvailableHeight;
private TextBlock[] Blocks;
private double ColumnWidth;
private bool IsTextRenderingAvailable;
public ReadableBlock() {
Loaded += ReadableBlock_Loaded;
}
private void ReadableBlock_Loaded(object sender, RoutedEventArgs e) {
LayoutUpdated += ReadableBlock_LayoutUpdated;
InvalidateArrange();
}
private void ReadableBlock_LayoutUpdated(object sender, object e) {
if (ActualWidth != AvailableWidth || ActualHeight != AvailableHeight) OnAvailableSizeChanged();
}
private void OnAvailableSizeChanged() {
IsTextRenderingAvailable = true;
AvailableWidth = ActualWidth;
AvailableHeight = ActualHeight;
double n = Columns;
double s = ColumnSpacing;
ColumnWidth = (AvailableWidth - ((n - 1d) * s))/n;
if (Blocks == null) CreateColumns();
RenderText();
}
private void CreateColumns() {
var container = new StackPanel { Orientation = Orientation.Horizontal };
var columns = Columns;
var spacing = ColumnSpacing;
var blocks = new List<TextBlock>();
TextBlock block;
for (int i = 0; i < columns; i++) {
blocks.Add(block = new TextBlock { TextWrapping = TextWrapping.Wrap, TextAlignment = TextAlignment, Width = ColumnWidth, Height = AvailableHeight });
if (i > 0) block.Margin = new Thickness(spacing, 0, 0, 0);
container.Children.Add(block);
}
base.Content = container;
Blocks = blocks.ToArray();
}
private int GetSplitOffset(string text) {
var m = new TextBlock { FontFamily = FontFamily, FontSize = FontSize, TextWrapping = TextWrapping.Wrap, TextAlignment = TextAlignment };
m.Text = text;
m.Measure(new Size(ColumnWidth, double.PositiveInfinity));
if (m.DesiredSize.Height < AvailableHeight) return -1;
var p = m.ContentStart;
var r = p.GetCharacterRect(LogicalDirection.Forward);
for (int i = 0, l = text.Length; i < l && r.Bottom < AvailableHeight; i++) {
p = p.GetPositionAtOffset(1, LogicalDirection.Forward);
r = p.GetCharacterRect(LogicalDirection.Forward);
}
return p.Offset - 2;
}
private bool SetBlock(int i, string text) {
if (i >= Blocks.Length) return false;
var block = Blocks[i];
block.Width = ColumnWidth;
block.Height = AvailableHeight;
block.Text = text;
return true;
}
private void RenderText() {
if (!IsTextRenderingAvailable || Text == null) return;
int i = 0, splitOffset = 0, n = Blocks.Length;
string text = Text;
for (i = 0; i < n; i++) Blocks[i].Text = "";
for (i = 0; i < n; i++) {
splitOffset = GetSplitOffset(text);
if (splitOffset > 0) {
if (!SetBlock(i, text.Substring(0, splitOffset))) return;
if (!SetBlock(i + 1, text = text.Substring(splitOffset))) return;
}
else {
SetBlock(i, text);
return;
}
}
}
}
}
一些XAML,並對其進行測試:
<Page
x:Class="ReadableBlockDemo.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ReadableBlockDemo"
xmlns:Controls="using:ReadableBlockDemo.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="#444"
Foreground="Gray"
>
<Grid>
<Controls:ReadableBlock Columns="4" ColumnSpacing="25" TextAlignment="Justify" Margin="25">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam tempor ipsum massa, ac lacinia libero sagittis lobortis. Donec pretium ex quis massa eleifend dignissim. Maecenas quis est odio. Proin facilisis mollis purus, vitae dapibus lacus interdum ac. Sed molestie id lorem vel volutpat. Ut vitae quam sem. Pellentesque convallis elementum ipsum commodo porttitor. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis sed porta eros. Pellentesque eget dolor euismod, fermentum orci vitae, ullamcorper mauris. Aliquam tempus hendrerit sollicitudin. Nunc sed erat quis ligula dictum convallis. Mauris eget finibus odio. Aenean sagittis congue purus, at elementum mi rhoncus ut. Suspendisse hendrerit dictum eleifend. Nullam scelerisque, eros ac euismod semper, velit sapien tincidunt purus, a tempus enim ante ut turpis. In vehicula arcu vitae nunc eleifend, id porta felis consequat.
Praesent vel tincidunt dui. Ut ut turpis lacus. Nullam accumsan laoreet elit eu suscipit. Cras aliquet pellentesque fringilla. Nullam ut consectetur nisi, non tristique quam. Suspendisse vitae gravida ipsum. Fusce ac enim non arcu rutrum sollicitudin. Aliquam in odio id tellus venenatis egestas et quis sapien. Etiam scelerisque ultrices tellus, quis dignissim leo gravida id.
Etiam ut elit tortor. Fusce fringilla accumsan urna eu viverra. Nunc porttitor lorem vitae magna ultrices lacinia. Etiam posuere sed dui nec gravida. Aenean fermentum turpis vehicula, blandit arcu id, mollis nulla. Praesent laoreet tellus vitae lectus consequat interdum. Duis interdum feugiat interdum.
Nam ut maximus est. Vestibulum sagittis eros ut diam ultrices eleifend. Praesent purus quam, luctus quis arcu at, interdum dapibus leo. Vivamus eget massa in leo malesuada egestas quis eget ipsum. Etiam consequat ullamcorper est, in ultricies lacus lobortis commodo. Nullam feugiat libero vitae convallis pellentesque. Pellentesque vitae tristique massa. In sollicitudin pretium nisl sit amet dignissim. Curabitur sodales fringilla ex, sit amet gravida lacus dignissim tempus. Aenean libero lectus, viverra eu eros in, pellentesque accumsan elit. Proin porttitor metus nulla, sit amet vulputate mauris finibus ut. Phasellus viverra risus sapien, eget sodales neque rhoncus vel. Nam quis ullamcorper nulla.
Duis sed ante dignissim, consequat orci in, iaculis nisi. Etiam nec interdum magna. Donec pharetra fermentum mi, eu aliquet diam hendrerit eget. Aenean vitae ligula sem. Sed at dignissim lorem. Proin vulputate massa eleifend, sagittis leo sit amet, condimentum mi. Curabitur nec vulputate nibh. Nunc ut dictum sapien. Praesent eu rhoncus lectus. Nullam eu auctor dui. Sed accumsan leo et ligula tempus semper. Suspendisse sed magna ut lectus pharetra malesuada.
Nullam pretium ligula non elit tempus imperdiet. In convallis a mauris vitae venenatis. Morbi pulvinar placerat ante nec tristique. Sed sodales leo in erat fermentum malesuada. Nullam vel turpis ut nulla tempus faucibus. Fusce dictum odio vel felis fringilla, a iaculis urna ultricies. Sed at mauris dolor. Aenean et vulputate libero, at sollicitudin leo. Morbi pretium gravida turpis ac bibendum. Aliquam lacinia mauris ut ante pharetra accumsan. Ut hendrerit, diam in iaculis egestas, justo magna pulvinar sapien, ut pellentesque purus orci id magna. Morbi egestas vestibulum dui, a ullamcorper turpis. Aenean molestie luctus lacus, vel pellentesque elit tincidunt sit amet. Suspendisse eu cursus enim. In eu libero a ipsum interdum aliquam quis blandit quam.
Fusce tortor nisi, pretium non dolor vitae, pretium condimentum ex. Cras facilisis odio tortor, et scelerisque quam volutpat non. Nam fermentum, velit in molestie venenatis, odio ante dapibus nulla, sed luctus ex urna sit amet lectus. Donec sit amet eros at nulla tempor venenatis. Cras nec purus porttitor dolor pretium auctor. Mauris sed ligula eget libero egestas tempus quis eu ipsum. Duis fermentum egestas libero. Praesent a mi ut felis facilisis pharetra id vel nulla.
Aenean dolor leo, placerat ac lobortis ut, tincidunt sit amet ex. Pellentesque at convallis massa. Vivamus fermentum eu augue vel sollicitudin. Donec dictum libero sem, et bibendum ex ultricies eget. Sed eu feugiat odio. Sed eget ex congue, dapibus magna ac, finibus diam. Nunc sollicitudin euismod dictum. Nullam rutrum mauris ut ipsum finibus, et euismod arcu sodales. In pellentesque molestie nunc, eget pellentesque metus varius et. Morbi augue nisl, aliquet eu scelerisque at, dictum eu elit. Quisque id ex quis urna facilisis rutrum nec in risus. Sed lorem justo, tempus at ante quis, cursus ultrices tellus. Donec lacinia varius lacus, vitae molestie velit auctor vitae. Aenean vulputate ullamcorper justo sit amet consectetur. Fusce vel risus mattis augue ultrices molestie. Donec sed rhoncus diam.
Nulla condimentum cursus massa semper suscipit. Cras non porta diam. Donec sed erat eu lectus vehicula hendrerit. Proin a ex tellus. Morbi aliquet dolor in ante lobortis, consequat aliquam dolor cursus. Sed molestie odio massa, a consectetur turpis pellentesque eget. Maecenas quis pharetra ligula, non rutrum libero. Aenean maximus nibh vel nisl elementum imperdiet. Integer et urna eu velit porttitor eleifend. Nunc et pharetra nisl. Nulla porttitor pellentesque mi. Suspendisse porta a ipsum at interdum.
</Controls:ReadableBlock>
</Grid>
</Page>
確定。沒有滾動,沒有格式,只是基礎知識。只是列,固定金額。 未經徹底測試,因此可能存在一兩個錯誤,但它應該可以在示例文本中正常工作。
我認爲如果我們允許格式化文本將會更困難。或者可能不是?那麼,這個例子拆分了純字符串。 TextBlock
曝光ContentStart
屬性,它允許我們獲取TextBlock
中所有字符的像素座標 - 如果它僅被測量。因此,我們創建了無形的TextBlock
- 將其寬度設置爲列寬度,我們搜索角色落在可用高度以外的索引。
這可叫我如何延長這個黑客以支持格式的文本,我認爲這個問題將變得非常「不平凡」;)
當你說文字你是指一個字符串,你只是想分開? –
輸入是一個字符串。從字符串資源讀取。但我想要列作爲結果。就像'FlowDocument'一樣,但是在UWP應用中也是如此。我有一個很長的描述,當它在整個屏幕上顯示時是不可讀的。我很驚訝在UWP中'FlowDocument'不可用。我發現沒有類似的控制。有'RichTextBlock',但它似乎沒有列支持。像微軟一樣,UWP只能用於小屏幕,這不是很「普遍」。 – Harry