数据模板在XAML中的条件呈现

数据模板在XAML中的条件呈现,xaml,uwp,uwp-xaml,Xaml,Uwp,Uwp Xaml,我有一个文本块列表,其中可能包含URL,如: 生成失败,请参阅此处的详细信息:http://... 建造成功 无法启动应用程序,请参阅此处的详细信息:http://... 我需要在UWP应用程序中显示这个(无休止的)列表。考虑到此列表可以在应用程序内的多个视图中使用,我将其作为一个通用模板: <ResourceDictionary> <ControlTemplate x:Key="ListItemTemplate" TargetType="ItemsControl"&g

我有一个文本块列表,其中可能包含URL,如:

  • 生成失败,请参阅此处的详细信息:http://...
  • 建造成功
  • 无法启动应用程序,请参阅此处的详细信息: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>

在此模板中,链接被视为常规文本(这是预期的)。据我所知,要使链接起作用,我需要将它们包装到
标记中,但我不能在模板中这样做,因为我不知道链接的确切位置和出现的数量

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

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

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;
            }
        }
    }
}

项目中的某个处理器

<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;
            }
        }
    }
}
公共静态类TextBlockExt
{
公共静态字符串GetXAMLText(TextBlock obj)
{
返回(字符串)obj.GetValue(XAMLTextProperty);
}
公共静态void SetXAMLText(TextBlock obj,字符串值)
{
对象设置值(XAMLTextProperty,value);
}
/// 
///将ViewModel中的原始字符串转换为文本块中的格式化文本:
/// 
///@“这是对文本的测试。”
/// 
///文本将被解析为XAML TextBlock内容。
/// 
///有关完整格式,请参阅WPF TextBlock文档。它支持跨距和所有类型的内容。
/// 
/// 
公共静态只读DependencyProperty XAMLTextProperty=
DependencyProperty.RegisterAttached(“XAMLText”、typeof(String)、typeof(TextBlockText),
新的PropertyMetadata(“,XAMLText_PropertyChanged));
私有静态void XAMLText_属性已更改(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
如果(d是文本块)
{
var ctl=d作为文本块;
尝试
{
//XAML需要具有默认命名空间的包含标记。我们正在分析
//TextBlock内容,因此将父级设置为TextBlock以使模式保持愉快。
//TODO:如果您希望任何内容不在默认模式中,那么您就倒霉了。
var值=e.NewValue;
var strText=String.Format(@“{0}”,e.NewValue);
TextBlock parsedContent=Windows.UI.Xaml.Markup.XamlReader.Load(strText)作为TextBlock;
//Inlines集合包含TextBlock的结构化XAML内容
ctl.Inlines.Clear();
var inlines=parsedContent.inlines.ToList();
parsedContent.Inlines.Clear();
//当新的父项出现时,UI元素将从源集合中删除
//获取它们,因此传入集合的副本以进行迭代。
控制内联线。连接(内联线);
ForEach(x=>ctl.inlines.Add(x));
}
捕获(例外情况除外)
{
System.Diagnostics.Debug.WriteLine(String.Format(“Ability.CAPS.WPF.UIExtensions.TextBlock.XAMLText_PropertyChanged:{0}”,ex.Message中的错误”);
投掷;
}
}
}
}
我不确定这是不是最好的方法,但它是有效的。我只需要预处理绑定值并将所有URL包装成超链接标记:

“App myapp”


我假设这应该适用于任何其他内容,例如

,您可以编写附加的行为,使用将字符串解析为XAML,并将结果控件添加到目标控件。它与
TextBlock
内容一起工作,内容可以包括
Hyperlink
。这是WPF而不是UWP;可能有一些不同

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

将第二部分放入值转换器会更干净。将其称为HyperLinksToXAMLConverter:

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


非常感谢!我测试了这个解决方案,它允许我修改内容和显示超链接。如前所述-代码应该稍微调整。@ragzovskii真棒。你能将UWP版本的代码添加到你的Q中,或者编辑到我的A中吗?我将批准该编辑。它应该适用于任何可以是
TextBlock
子项的内容。