WP开发笔记-实现类似微博用户名+链接的解析

实现类似微博内容里,用户名+Url的解析效果。

注:这里使用的数据是twitter的格式,可能跟微博的不一样。但是原理是相通的。 

原理:使用richtextbox。

将正文内容用正则表达式解析之后,获取每一个的匹配的index, 然后按照index排序。

遍历每一个匹配项,把文本作为run动态添加到richtextbox;把用户名作为hyperlink添加到richtextbox。 

原始数据大概是这样

{
    "id": 174858924, 
    "id_str": "174858924", 
    "name": "喔喔(必须同意许可协议才能查看推文)", 
    "screen_name": "im_wower",
    "description": "@Chicken4WP
	gmail/gtalk: [email protected]",
}

用户名的正则:

private static Regex UserNameRegex = new Regex(@"([^A-Za-z0-9_]|^)@(?<name>(_*[A-Za-z0-9]{1,15}_*)+)(?![A-Za-z0-9_@])");
说明:仅限twitter的用户名。

解析用户名:

public static IEnumerable<EntityBase> ParseUserMentions(string text)
{
    if (string.IsNullOrEmpty(text))
        yield break;
    var matches = UserNameRegex.Matches(text);
    foreach (Match match in matches)
    {
        var entity = new UserMention
        {
            Index = match.Groups["name"].Index - 1,//remove @
            DisplayName = match.Groups["name"].Value
        };
        yield return entity;
    }
}

UserMention是一个Entity类。

public class UserMention : EntityBase
{
    public override EntityType EntityType
    {
        get
        {
            return EntityType.UserMention;
        }
    }

    public string Id { get; set; }

    public string DisplayName { get; set; }

    public override string Text
    {
        get
        {
            return "@" + DisplayName;
        }
    }
}
EntityBase类:
public class EntityBase
{
    public virtual EntityType EntityType { get; private set; }

    public int Index { get; set; }

    public virtual string Text { get; set; }
}

public enum EntityType
{
    None = 0,
    Media = 1,
    HashTag = 2,
    Url = 3,
    UserMention = 4,
}
添加一个继承自RichTextBox的类:
public class AutoRichTextBox : RichTextBox
注册依赖属性:
public static DependencyProperty TweetDataProperty =
DependencyProperty.Register("TweetData", typeof(ModelBase), typeof(AutoRichTextBox), new PropertyMetadata(TweetDataPropertyChanged));

依赖属性的回调:

public static void TweetDataPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
    #region init
    var textBox = sender as AutoRichTextBox;
    if (textBox == null || e.NewValue == null)
        return;
    textBox.AddTweetData(e.NewValue);
}
动态生成控件:
private void AddTweetData(object data)
{
    this.Blocks.Clear();
    string text = string.Empty;
    var paragraph = new Paragraph();
    var entities = new List<EntityBase>();
    #region tweet
    if (data is TweetBase)
    {
        var tweet = data as TweetBase;
        text = tweet.Text;
        #region add entity
        if (tweet.Entities.UserMentions != null && tweet.Entities.UserMentions.Count != 0)
        {
            entities.AddRange(TwitterHelper.ParseUserMentions(text, tweet.Entities.UserMentions));
        }
        if (tweet.Entities.HashTags != null && tweet.Entities.HashTags.Count != 0)
        {
            entities.AddRange(TwitterHelper.ParseHashTags(text, tweet.Entities.HashTags));
        }
        if (tweet.Entities.Urls != null && tweet.Entities.Urls.Count != 0)
        {
            entities.AddRange(TwitterHelper.ParseUrls(text, tweet.Entities.Urls));
        }
        if (tweet.Entities.Medias != null && tweet.Entities.Medias.Count != 0)
        {
            entities.AddRange(TwitterHelper.ParseMedias(text, tweet.Entities.Medias));
        }
        #endregion
    }
    #endregion
    #region profile
    else if (data is UserProfileDetail)
    {
        var profile = data as UserProfileDetail;
        text = profile.Text;
        var mentions = TwitterHelper.ParseUserMentions(profile.Text);
        entities.AddRange(mentions);
        var hashtags = TwitterHelper.ParseHashTags(profile.Text);
        entities.AddRange(hashtags);
        #region url
        if (profile.UserProfileEntities != null &&
            profile.UserProfileEntities.DescriptionEntities != null &&
            profile.UserProfileEntities.DescriptionEntities.Urls != null)
        {
            var parsedUrls = TwitterHelper.ParseUrls(profile.Text, profile.UserProfileEntities.DescriptionEntities.Urls);
            entities.AddRange(parsedUrls);
        }
        #endregion
    }
    #endregion
    #endregion
    #region none
    if (entities.Count == 0)
    {
        paragraph.Inlines.Add(new Run
        {
            Text = HttpUtility.HtmlDecode(text)
        });
        this.Blocks.Add(paragraph);
    }
    #endregion
    #region add
    else
    {
        #region replace
        int index = 0;
        foreach (var entity in entities.OrderBy(v => v.Index))
        {
            #region starter
            if (index < entity.Index)
            {
                paragraph.Inlines.Add(new Run
                {
                    Text = HttpUtility.HtmlDecode(text.Substring(index, entity.Index - index)),
                });
                index = entity.Index;
            }
            #endregion
            var hyperlink = new Hyperlink();
            hyperlink.TextDecorations = null;
            hyperlink.Foreground = App.PhoneAccentBrush;
            #region entity
            switch (entity.EntityType)
            {
                #region mention, hashtag
                case EntityType.UserMention:
                case EntityType.HashTag:
                    hyperlink.CommandParameter = entity;
                    hyperlink.Click += this.Hyperlink_Click;
                    hyperlink.Inlines.Add(entity.Text);
                    break;
                #endregion
                #region media, url
                case EntityType.Media:
                    var media = entity as MediaEntity;
                    hyperlink.NavigateUri = new Uri(media.MediaUrl, UriKind.Absolute);
                    hyperlink.TargetName = "_blank";
                    hyperlink.Inlines.Add(media.TruncatedUrl);
                    break;
                case EntityType.Url:
                    var url = entity as UrlEntity;
                    hyperlink.NavigateUri = new Uri(url.ExpandedUrl, UriKind.Absolute);
                    hyperlink.TargetName = "_blank";
                    hyperlink.Inlines.Add(url.TruncatedUrl);
                    break;
                #endregion
            }
            #endregion
            paragraph.Inlines.Add(hyperlink);
            index += entity.Text.Length;
        }
        #region ender
        if (index < text.Length)
        {
            paragraph.Inlines.Add(new Run
            {
                Text = HttpUtility.HtmlDecode(text.Substring(index, text.Length - index)),
            });
        }
        #endregion
        #endregion
        this.Blocks.Add(paragraph);
    }
    #endregion
}

一些说明:

0. 为什么不使用xaml.parse(string)动态生成控件?

    因为转义字符很麻烦。而且动态生成控件需要加入命名空间,比较麻烦。

截图效果(来自Chicken4WP)

WP开发笔记-实现类似微博用户名+链接的解析_第1张图片

示例代码:

呃,没有示例代码。。可以查看Chicken4WP的源码>>

你可能感兴趣的:(windows,wp,phone,Chicken)