【问题标题】:Conditional rendering of the data template in XAMLXAML 中数据模板的条件呈现
【发布时间】:2017-01-05 01:44:25
【问题描述】:

我有一个文本块列表,里面可能包含 url,smth 之类的:

  • 构建失败,请在此处查看更多信息: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>

在此模板中,链接被视为常规文本(这是预期的)。据我了解,要使链接正常工作,我需要将它们包装到 &lt;HyperLink&gt; 标记中,但我不能在模板中这样做,因为我不知道链接的确切位置以及其中会出现多少。

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

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

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 &lt;Hyperlink NavigateUri=\"http://app/\"&gt;myapp&lt;/Hyperlink&gt;"

我认为这应该适用于任何其他内容,例如 &lt;InlineUIContainer&gt;

【问题讨论】:

  • 它应该适用于任何可以是TextBlock 子级的内容。

标签: xaml uwp uwp-xaml


【解决方案1】:

您可以编写附加行为,使用XamlReader.Load(Stream) 将字符串解析为 XAML,并将生成的控件添加到目标控件。 Here's one I wroteTextBlock 内容一起使用,其中可以包括 Hyperlink。那是针对 WPF 而不是 UWP;可能会有一些差异。

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

将第二部分放在值转换器中会更简洁。叫它HyperLinksToXAMLConverter

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

【讨论】:

  • 非常感谢!我测试了这个解决方案,它允许我修改内容并显示超链接。如前所述 - 代码应稍作调整。
  • @ragzovskii 太棒了。您可以将 UWP 版本的代码添加到您的 Q 中,或者将其编辑到我的 A 中吗?我会批准修改。
猜你喜欢
  • 2017-06-21
  • 1970-01-01
  • 2023-04-06
  • 2014-04-14
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
  • 2019-10-27
相关资源
最近更新 更多