c# - 如果在 WinRT 中设置为绑定(bind),则不会设置自定义模板控件的依赖属性

标签 c# xaml windows-runtime uwp

我编写了一个自定义模板化 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/

相关文章:

c# - 如何在 Metro 应用程序中打印文本文件或文本框的内容?

c# - 如何在Windows应用商店应用程序关闭时保存数据?

c# - 在 Windows 8 中处理方向

c# - 无法使用数据注释

c# - 在 FlipView 中使用 ScrollViewer

c# - WinRTXAML 工具包 BindableSelection 无法正常工作

javascript - Windows 8 应用程序(html 和 Javascript): alternate way to show image from picture library (other that file picker)

c# - 单击链接时弹出

c# - 最好的设计模式是什么?

.net - 如何在 XAML 中引用当前对象