在XAML

时间:2017-01-04 14:35:45

标签: xaml uwp uwp-xaml

我有一个文本块列表,可能包括内部网址,如:

  • 构建失败,请点击此处:http:// ...
  • 构建成功
  • 无法启动应用http://myapp/,请点击此处:http:// ...

我需要在UWP应用中显示此(无尽的)列表。考虑到此列表可以在应用程序内的多个视图中使用,我将其作为一个通用模板:

<ResourceDictionary>
  <ControlTemplate x:Key="ListItemTemplate" TargetType="ItemsControl">
    <Grid>
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="50"/>
        <ColumnDefinition Width="*"/>
      </Grid.ColumnDefinitions>
      <Image Grid.Column="0" Source="{Binding image_url}"/>
      <TextBlock Grid.Column="1" Text="{Binding status}"/>
    </Grid>
  </ControlTemplate>
</ResourceDictionary>

在此模板中,链接被视为常规文本(预期)。据我了解,要使链接工作,我需要将它们包装到<HyperLink>标记中,但我不能在模板中执行此操作,因为我不知道链接的确切位置以及将显示多少链接。

有没有办法实现一些渲染器方法,可以在代码中生成项目的主体(<TextBlock>),处理传递的值?

可能转换器可以帮助我,但如果我理解正确,它只接受来自绑定的值,我需要引用整个实例。

UPD :从接受的答案中扩展解决方案:

资源字典

<ResourceDictionary xmlns:resources="using:NamespaceWithTextBlockExt">
  <ControlTemplate x:Key="ListItemTemplate" TargetType="ItemsControl">
    <Grid>
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="50"/>
        <ColumnDefinition Width="*"/>
      </Grid.ColumnDefinitions>
      <Image Grid.Column="0" Source="{Binding image_url}"/>
      <TextBlock Grid.Column="1" resources:TextBlockExt.XAMLText="{Binding Text}"/>
    </Grid>
  </ControlTemplate>
</ResourceDictionary>

项目中的处理器

public static class TextBlockExt
{
    public static String GetXAMLText(TextBlock obj)
    {
        return (String)obj.GetValue(XAMLTextProperty);
    }

    public static void SetXAMLText(TextBlock obj, String value)
    {
        obj.SetValue(XAMLTextProperty, value);
    }

    /// <summary>
    /// Convert raw string from ViewModel into formatted text in a TextBlock: 
    /// 
    /// @"This <Bold>is a test <Italic>of the</Italic></Bold> text."
    /// 
    /// Text will be parsed as XAML TextBlock content. 
    /// 
    /// See WPF TextBlock documentation for full formatting. It supports spans and all kinds of things. 
    /// 
    /// </summary>
    public static readonly DependencyProperty XAMLTextProperty =
        DependencyProperty.RegisterAttached("XAMLText", typeof(String), typeof(TextBlockExt),
                                             new PropertyMetadata("", XAMLText_PropertyChanged));

    private static void XAMLText_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is TextBlock)
        {
            var ctl = d as TextBlock;

            try
            {
                //  XAML needs a containing tag with a default namespace. We're parsing 
                //  TextBlock content, so make the parent a TextBlock to keep the schema happy. 
                //  TODO: If you want any content not in the default schema, you're out of luck. 
                var value = e.NewValue;

                var strText = String.Format(@"<TextBlock xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"">{0}</TextBlock>", e.NewValue);

                TextBlock parsedContent = Windows.UI.Xaml.Markup.XamlReader.Load(strText) as TextBlock;

                //  The Inlines collection contains the structured XAML content of a TextBlock
                ctl.Inlines.Clear();

                var inlines = parsedContent.Inlines.ToList();
                parsedContent.Inlines.Clear();

                //  UI elements are removed from the source collection when the new parent 
                //  acquires them, so pass in a copy of the collection to iterate over. 
                ctl.Inlines.Concat(inlines);
                inlines.ForEach(x => ctl.Inlines.Add(x));
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(String.Format("Error in Ability.CAPS.WPF.UIExtensions.TextBlock.XAMLText_PropertyChanged: {0}", ex.Message));
                throw;
            }
        }
    }
}

我不确定这是最好的方法,但它确实有效。我只需要预处理绑定值并将所有URL包装成超链接标记:

"App <Hyperlink NavigateUri=\"http://app/\">myapp</Hyperlink>"

我认为这应该适用于任何其他内容,例如<InlineUIContainer>

1 个答案:

答案 0 :(得分:1)

您可以编写一个附加行为,使用XamlReader.Load(Stream)将字符串解析为XAML,并将生成的控件添加到目标控件。 Here's one I wrote使用TextBlock内容进行处理,其中包含Hyperlink。那是WPF而不是UWP;可能存在一些差异。

你需要做一些额外的工作:它需要一个非XAML字符串,在解析为XAML之前,它必须找到URL并用字符串中的XAML Hyperlink元素替换它们。然后你要解析那个。

将第二部分放入值转换器会更清晰。称之为HyperLinksToXAMLConverter

<TextBlock
    local:XAMLText="{Binding status, Converter={StaticResource HyperLinksToXAML}}"
    />