我编写了一个自定义模板化 RichTextBlock,以便将表情符号和链接分别表示为图像和超链接按钮。它基本上只有一个“文本”依赖属性,因为当收到纯文本/字符串时,所有转换工作都将在控件内部进行处理。
问题是,如果 Text 属性带有某些特定字符串,例如 Text="asdasdsa",则控件将正确表示“asdasdas”。如果属性设置为绑定(bind)类似 Text="{Binding Something}"的内容,则控件将无法工作,并且 setter Text 依赖属性将永远不会触发。
控件的样式基本是这样的
<Style TargetType="local:MyRichTextBlock" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:MyRichTextBlock">
<Border HorizontalAlignment="Center" Width="auto" Height="auto">
<StackPanel>
<RichTextBlock x:Name="ChildRichTextBlock"/>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
基本上,它会转换纯文本并替换 XAML 中的表情符号和超链接,最后将 XAML 代码块作为段落添加到 RichTextBlock 中。
控件的代码
public sealed class MyRichTextBlock : Control
{
RichTextBlock _richTextBlock;
StringBuilder builder = new StringBuilder();
Regex urlRx = new Regex(@"(?<url>(http:[/][/]|www.)([a-z]|[A-Z]|[0-9]|[/.]|[~])*)", RegexOptions.IgnoreCase);
public MyRichTextBlock()
{
this.DefaultStyleKey = typeof(MyRichTextBlock);
foreach (var key in emojiDict.Keys)
{
builder.Append(key.Replace("[", @"\[").Replace("]", @"\]"));
builder.Append("|");
}
builder.Remove(builder.Length - 1, 1);
}
private readonly Dictionary<string, string> emojiDict = new Dictionary<string, string>
{
//Dictionary of emojis key
};
protected override void OnApplyTemplate()
{
_richTextBlock = GetTemplateChild("ChildRichTextBlock") as RichTextBlock;
SetRichTextBlock(Text);
}
public String Text
{
get { return (String)GetValue(TextProperty); }
set { SetValue(TextProperty, value); } //This setter won't fire
}
// Using a DependencyProperty as the backing store for Text. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(String), typeof(MyRichTextBlock), new PropertyMetadata(""));
//Conversion work, it does not really related to the property I think
private void SetRichTextBlock(string value)
{
string abc = value;
MatchCollection matches = urlRx.Matches(value);
var r = new Regex(builder.ToString());
var mc = r.Matches(value);
foreach (Match m in mc)
{
value = value.Replace(m.Value, string.Format(@"<InlineUIContainer><Border><Image Source=""ms-appx:///Assets/Emoji/{0}.png"" Margin=""2,0,2,0"" Width=""30"" Height=""30""/></Border></InlineUIContainer>", emojiDict[m.Value]));
}
foreach (Match match in matches)
{
string url = match.Groups["url"].Value;
value = value.Replace(url,
string.Format("<InlineUIContainer><Border><HyperlinkButton Margin=\"0,0,0,-4\" Padding=\"0,2,0,0\" NavigateUri =\"{0}\"><StackPanel HorizontalAlignment=\"Center\" Height=\"25\" Width=\"90\" Background=\"#FFB8E9FF\" Orientation = \"Horizontal\"><Image Margin=\"5,0,0,0\" Source = \"/Assets/Link.png\" Width = \"15\" Height = \"15\"/><TextBlock Margin=\"4,2.5,0,0\" Text=\"网页链接\" Foreground=\"White\" FontFamily=\"Microsoft YaHei UI\" FontSize=\"14\" FontWeight=\"Bold\"/></StackPanel ></HyperlinkButton></Border></InlineUIContainer>", url));
}
value = value.Replace("\r\n", "<LineBreak/>");
var xaml = string.Format(@"<Paragraph
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"">
<Paragraph.Inlines>
<Run></Run>
{0}
</Paragraph.Inlines>
</Paragraph>", value);
var p = (Paragraph)XamlReader.Load(xaml);
_richTextBlock.Blocks.Add(p);
}
}
以及我如何使用这个控件的方式
<DataTemplate x:Name="NormalTemplate">
<Grid Grid.Column="1"
Grid.Row="1"
d:LayoutOverrides="LeftMargin, RightMargin, TopMargin, BottomMargin"
Margin="0,15,0,15"
Name="NormalTemplateGrid">
//Codes omit//
<local:MyRichTextBlock x:Name="WeiboTextTextblock"
Margin="20,35,0,0"
Text="{Binding Text}"
Grid.Column="2"
Grid.Row="1"
d:LayoutOverrides="HorizontalAlignment, TopMargin, BottomMargin, LeftPosition, RightPosition, TopPosition, BottomPosition"
HorizontalAlignment="Left"
FontFamily="Microsoft YaHei"/>
</Grid>
</DataTemplate>
您知道问题是什么以及解决方案是什么吗?
最佳答案
setter 的存在只是为了完成依赖属性。您需要为您的 Text
属性定义一个属性更改回调,如下所示 -
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register(nameof(Text), typeof(String), typeof(MyRichTextBlock), new PropertyMetadata("", OnTextChange));
private static void OnTextChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var rtb = (MyRichTextBlock)d;
rtb.SetRichTextBlock(e.NewValue.ToString());
}
关于c# - 如果在 WinRT 中设置为绑定(bind),则不会设置自定义模板控件的依赖属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35031511/