更新 #2:
这是可能的 WinRT 版本。
第 1 部分 - Xaml 代码(用户控件),此处 WinRtApp 是定义用户控件的项目。如果您想使用其他 ContentTemplate 来呈现您的数据(例如推文),您应该解析您的文本并添加一个新模型(例如 TweetPart),看看我是如何使用 HyperlinkButton 完成的,添加新的 DataTemplate 并扩展 ContentTemplateSelector。
<UserControl
x:Class="WinRtApp.ComplexTextPresenter"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400" x:Name="This">
<Grid>
<Grid.Resources>
<DataTemplate x:Key="HyperlinkDataTemplateKey">
<HyperlinkButton Margin="0" FontSize="12" CommandParameter="{Binding }" Command="{Binding ElementName=This, Path=OnHyperlinkCommand}" Content="{Binding Path=Content}" Foreground="Blue"/>
</DataTemplate>
<DataTemplate x:Key="LiteralDataTemplateKey">
<TextBlock Margin="0" FontSize="12" Text="{Binding Path=Content}"></TextBlock>
</DataTemplate>
<MyDataTemplateSelector x:Key="DataTemplateSelectorKey"
LiteralDataTemplate ="{StaticResource LiteralDataTemplateKey}"
HyperlinkDataTemplate="{StaticResource HyperlinkDataTemplateKey}"/>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,0,0"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<Rectangle Fill="Green" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
<ListBox ItemsSource="{Binding ElementName=This, Path=InputCollection}" ItemTemplateSelector="{StaticResource DataTemplateSelectorKey}" Margin="5">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ListBox>
</Grid>
第 2 节 - Xaml 背后的代码
public sealed partial class ComplexTextPresenter : UserControl
{
public static readonly DependencyProperty InputProperty = DependencyProperty.Register("Input", typeof(string), typeof(MainPage), new PropertyMetadata(default(string), InputPropertyChangedCallback));
private static void InputPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
var ctrl = dependencyObject as ComplexTextPresenter;
if(ctrl == null)
return;
ctrl.Init();
}
public static readonly DependencyProperty InputCollectionProperty = DependencyProperty.Register("InputCollection", typeof(ObservableCollection<object>), typeof(MainPage), new PropertyMetadata(default(ObservableCollection<object>)));
public static readonly DependencyProperty OnHyperlinkCommandProperty = DependencyProperty.Register("OnHyperlinkCommand", typeof(ICommand), typeof(MainPage), new PropertyMetadata(default(ICommand)));
private IEnumerable<object> GetParsedInput()
{
List<BaseInputPart> inputParts = new List<BaseInputPart>();
var strings = Input.Split(new[] { " " }, StringSplitOptions.None).ToList();
strings.ForEach(s =>
{
if (s.IsHyperlink())
{
inputParts.Add(new HyperLinkPart { Content = s });
}
else
{
inputParts.Add(new LiteralPart { Content = s });
}
});
return inputParts.OfType<object>().ToList();
}
public string Input
{
get { return (string)GetValue(InputProperty); }
set { SetValue(InputProperty, value); }
}
public ObservableCollection<object> InputCollection
{
get { return (ObservableCollection<object>)GetValue(InputCollectionProperty); }
private set { SetValue(InputCollectionProperty, value); }
}
public ICommand OnHyperlinkCommand
{
get { return (ICommand)GetValue(OnHyperlinkCommandProperty); }
set { SetValue(OnHyperlinkCommandProperty, value); }
}
private void Init()
{
InputCollection = new ObservableCollection<object>(GetParsedInput());
}
public ComplexTextPresenter()
{
this.InitializeComponent();
}
}
public abstract class BaseInputPart
{
public abstract string Content { get; set; }
}
public class HyperLinkPart : BaseInputPart
{
public override string Content { get; set; }
}
public class LiteralPart : BaseInputPart
{
public override string Content { get; set; }
}
public static class StringExtension
{
#region hyperlink regex region
private static readonly Regex UrlRegex =
new Regex(
@"(?#Protocol)(?:(?:ht|f)tp(?:s?)\:\/\/|~/|/)?(?#Username:Password)(?:\w+:\w+@)?(?#Subdomains)(?:(?:[-\w]+\.)+(?#TopLevel Domains)(?:com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|museum|travel|[a-z]{2}))(?#Port)(?::[\d]{1,5})?(?#Directories)(?:(?:(?:/(?:[-\w~!$+|.,=]|%[a-f\d]{2})+)+|/)+|\?|#)?(?#Query)(?:(?:\?(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)(?:&(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)*)*(?#Anchor)(?:#(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)?");
#endregion
public static bool IsHyperlink(this string word)
{
var result = false;
try
{
// First check to make sure the word has at least one of the characters we need to make a hyperlink
if (word.IndexOfAny(@":.\/".ToCharArray()) != -1)
{
if (Uri.IsWellFormedUriString(word, UriKind.Absolute))
{
// The string is an Absolute URI
result = true;
}
else if (UrlRegex.IsMatch(word))
{
Uri uri = new Uri(word, UriKind.RelativeOrAbsolute);
if (!uri.IsAbsoluteUri)
{
// rebuild it it with http to turn it into an Absolute URI
uri = new Uri(@"http://" + word, UriKind.Absolute);
result = true;
}
if (uri.IsAbsoluteUri)
{
result = true;
}
}
else
{
Uri wordUri = new Uri(word);
// Check to see if URL is a network path
if (wordUri.IsUnc || wordUri.IsFile)
{
result = true;
}
}
}
}
catch (Exception e)
{
result = false;
}
return result;
}
}
更新 #4 - 选择器代码(添加为新类)
public class MyDataTemplateSelector : DataTemplateSelector
{
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
if (item is HyperLinkPart)
return HyperlinkDataTemplate;
if (item is LiteralPart)
return LiteralDataTemplate;
return null;
}
public DataTemplate LiteralDataTemplate { get; set; }
public DataTemplate HyperlinkDataTemplate
{ get; set; }
}
如何使用 - MainPage xaml 代码
<Page
x:Class="PutHereTheNameOfYourProject.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ComplexTextPresenter x:Name="ComplexTextPresenter"/>
如何使用 - MainPage xaml 代码背后
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Required;
Init();
}
private void Init()
{
ComplexTextPresenter.Input =
@"I Love https://www.google.com site. I Love https://www.google.com site. I Love https://www.google.com site. I Love https://www.google.com site. I Love https://www.google.com site. I Love https://www.google.com site. I Love https://www.google.com site.";
ComplexTextPresenter.OnHyperlinkCommand = new RelayCommand<object>(Execute);
}
private void Execute(object o)
{
//put here the code that can open browser
}
}
中继指令代码
public class RelayCommand<T> : ICommand
{
readonly Action<T> _execute;
readonly Func<T, bool> _canExecute;
public event EventHandler CanExecuteChanged;
public RelayCommand(Action<T> execute, Func<T, bool> canExecute = null)
{
_execute = execute;
_canExecute = canExecute;
}
public void RefreshCommand()
{
var cec = CanExecuteChanged;
if (cec != null)
cec(this, EventArgs.Empty);
}
public bool CanExecute(object parameter)
{
if (_canExecute == null) return true;
return _canExecute((T)parameter);
}
public void Execute(object parameter)
{
_execute((T)parameter);
}
}
更新 #3
- WinRt 是我的项目名称,您需要使用您的项目名称。
- 创建名为 ComplexTextPresenter 的用户控件。
- 将 UserControl 的 xaml 替换为第 1 节中定义的代码。
- 将 UserControl 的代码隐藏替换为第 2 节中定义的代码。
- 将第 3 节中定义的 RelayCommand 代码作为一个类添加到您的项目中。
- 阅读this article,关于如何在XAML中添加引用。
- 为了在您的项目中获取 Wrappanel,请在 VS 工具/NuGet 包管理器/包管理器控制台中运行下一个 NuGet 命令:Install-Package WPtoolkit(taken from here)。
- 下载ReSharper,它将帮助您管理所有与程序集导入相关的问题。