考虑以下标记声明:
<TextBlock>
<Run>abcdefghijklmnopqrstuvwxyz</Run>
<LineBreak/>
<Run>0123456789</Run>
</TextBlock>
我想将任何数据绑定到TextBlock并将此数据转换为InlineCollection。使用Data Binding执行此操作会非常优雅。另一种方法是观察我的数据源并使用Code Behind中TextBlock类的Inlines-Property。
我尝试了以下但是没有用:
<TextBlock>
<Binding Path="MyDataSource" Converter="{StaticResource MyTextConverter}"/>
</TextBlock>
我想要做的是通过将我的TextBlock封装在ViewBox中来实现自动字体缩放,还可以在任意字母数后生成LineBreaks。
提前感谢您的帮助。 最好的问候。
答案 0 :(得分:2)
这很容易成为现实...... "\r\n"
在正确的位置完成工作。
答案 1 :(得分:1)
我使用this答案来解决与WPF相关的问题,以提出可以向Silverlight中的TextBlock添加简单格式的Silverlight行为。格式化是通过Xml元素完成的,这些元素的工作方式与在元素本身中格式化TextBlock的方式类似。可以使用粗体,斜体,下划线和LineBreak元素。
首先,行为定义如下:
public static class FormattedTextBlockBehavior
{
public static string GetFormattedText(DependencyObject obj)
{
return (string) obj.GetValue(FormattedTextProperty);
}
public static void SetFormattedText(DependencyObject obj, string value)
{
obj.SetValue(FormattedTextProperty, value);
}
public static readonly DependencyProperty FormattedTextProperty =
DependencyProperty.RegisterAttached("FormattedText",
typeof (string),
typeof (FormattedTextBlockBehavior),
new PropertyMetadata("", FormattedTextChanged));
private static Inline Traverse(string value)
{
// Get the sections/inlines
string[] sections = SplitIntoSections(value);
// Check for grouping
if (sections.Length.Equals(1))
{
string section = sections[0];
string token; // E.g <Bold>
int tokenStart, tokenEnd; // Where the token/section starts and ends.
// Check for token
if (GetTokenInfo(section, out token, out tokenStart, out tokenEnd))
{
// Get the content to further examination
string content = token.Length.Equals(tokenEnd - tokenStart)
? null
: section.Substring(token.Length, section.Length - 1 - token.Length*2);
switch (token)
{
case "<Bold>":
var b = new Bold();
b.Inlines.Add(Traverse(content));
return b;
case "<Italic>":
var i = new Italic();
i.Inlines.Add(Traverse(content));
return i;
case "<Underline>":
var u = new Underline();
u.Inlines.Add(Traverse(content));
return u;
case "<LineBreak/>":
return new LineBreak();
case "<LineBreak />":
return new LineBreak();
default:
return new Run
{
Text = section
};
}
}
return new Run
{
Text = section
};
}
var span = new Span();
foreach (string section in sections)
span.Inlines.Add(Traverse(section));
return span;
}
/// <summary>
/// Examines the passed string and find the first token, where it begins and where it ends.
/// </summary>
/// <param name="value">The string to examine.</param>
/// <param name="token">The found token.</param>
/// <param name="startIndex">Where the token begins.</param>
/// <param name="endIndex">Where the end-token ends.</param>
/// <returns>True if a token was found.</returns>
private static bool GetTokenInfo(string value, out string token, out int startIndex, out int endIndex)
{
token = null;
endIndex = -1;
startIndex = value.IndexOf("<");
int startTokenEndIndex = value.IndexOf(">");
// No token here
if (startIndex < 0)
return false;
// No token here
if (startTokenEndIndex < 0)
return false;
token = value.Substring(startIndex, startTokenEndIndex - startIndex + 1);
// Check for closed token. E.g. <LineBreak/>
if (token.EndsWith("/>"))
{
endIndex = startIndex + token.Length;
return true;
}
string endToken = token.Insert(1, "/");
// Detect nesting;
int nesting = 0;
int pos = 0;
do
{
int tempStartTokenIndex = value.IndexOf(token, pos);
int tempEndTokenIndex = value.IndexOf(endToken, pos);
if (tempStartTokenIndex >= 0 && tempStartTokenIndex < tempEndTokenIndex)
{
nesting++;
pos = tempStartTokenIndex + token.Length;
}
else if (tempEndTokenIndex >= 0 && nesting > 0)
{
nesting--;
pos = tempEndTokenIndex + endToken.Length;
}
else // Invalid tokenized string
return false;
} while (nesting > 0);
endIndex = pos;
return true;
}
/// <summary>
/// Splits the string into sections of tokens and regular text.
/// </summary>
/// <param name="value">The string to split.</param>
/// <returns>An array with the sections.</returns>
private static string[] SplitIntoSections(string value)
{
var sections = new List<string>();
while (!string.IsNullOrEmpty(value))
{
string token;
int tokenStartIndex, tokenEndIndex;
// Check if this is a token section
if (GetTokenInfo(value, out token, out tokenStartIndex, out tokenEndIndex))
{
// Add pretext if the token isn't from the start
if (tokenStartIndex > 0)
sections.Add(value.Substring(0, tokenStartIndex));
sections.Add(value.Substring(tokenStartIndex, tokenEndIndex - tokenStartIndex));
value = value.Substring(tokenEndIndex); // Trim away
}
else
{
// No tokens, just add the text
sections.Add(value);
value = null;
}
}
return sections.ToArray();
}
private static void FormattedTextChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var value = e.NewValue as string;
var textBlock = sender as TextBlock;
if (textBlock != null)
textBlock.Inlines.Add(Traverse(value));
}
然后,从xaml本身,行为可以如下引用:
xmlns:Helpers="clr-namespace:Namespace.Helpers"
<TextBlock Grid.Row="0" Margin="10,10,10,10" TextWrapping="Wrap" FontSize="14" Helpers:FormattedTextBlockBehavior.FormattedText="{Binding ViewModel.Text}" />
答案 2 :(得分:0)
我猜你只需要将转换器分配给TextBlock的TextProperty。
然后您的转换器会添加\r\n
以在需要时添加换行符。
答案 3 :(得分:0)
我想我通过对TextBlock进行子类化以使InlineCollection可绑定并在xaml标记的String和InlineCollection(或Inlines的通用列表)之间编写转换器来回答这个问题。]
正如infografnet所指出的,TextBlock
类的Silverlight版本为sealed
,这使我的WPF子分类建议无效。