У меня есть список текстовых блоков, которые могут включать в себя URLs внутри, как чему-л:Условный рендеринг шаблона данных в XAML
- Строить не удалось, смотрите здесь: Http: // ...
- Сложение удалось
- App 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;
}
}
}
}
Я не уверен, что это лучший способ, bu Это работает. Мне просто нужно Preprocess связанного значения и завернуть все адреса в теги гиперссылка:
"App <Hyperlink NavigateUri=\"http://app/\">myapp</Hyperlink>"
Я предполагаю, что это должно работать с любым другим контентом, как <InlineUIContainer>
Он должен работать с любым контентом, который может быть дочерним элементом TextBlock. –