2016-07-05 19 views
1

UWPのURL、電子メール、電話番号を自動的に強調したいと思います。 Androidでは可能ですが、この機能はMicrosoftによって忘れられているようです。 私の場合、Webサービスからテキストを取得するので、Webプラットフォーム上のユーザーテキスト入力であるテキスト形式はわかりません。URL、電話番号、電子メールをTextBlockで自動検出

答えて

5

プラットフォームはまだこの機能をサポートしていません。

  • は、URL、電話番号を抽出するために、いくつかの正規表現を使うフォーマットするテキストを受信添付プロパティを作成します。私は同じことをやってきたとき、私はしている私自身の溶液で終了しました、
  • それから、電子メールアドレスは、私が使用する正規表現は、例の多くをカバーしているが、いくつかのエッジケースがまだ不足していることができる付属のTextBlockコントロールに

を注入していますインラインコレクションを生成します。添付プロパティコード

<TextBlock uwpext:TextBlock.InteractiveText="Here is a link www.bing.com to send to [email protected] or 0000000000" /> 

それは、この方法を使用しているあなたのコードのための

// ------------------------------------------------------------------------------------------- 
    /// <summary> 
    /// The regex to detect the URL from the text content 
    /// It comes from https://gist.github.com/gruber/249502 (http://daringfireball.net/2010/07/improved_regex_for_matching_urls) 
    /// </summary> 
    private static readonly Regex UrlRegex = new Regex(@"(?i)\b((?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'"".,<>?«»“”‘’]))", RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(500)); 

    // ------------------------------------------------------------------------------------------- 
    /// <summary> 
    /// The regex to detect the email addresses 
    /// It comes from https://msdn.microsoft.com/en-us/library/01escwtf.aspx 
    /// </summary> 
    private static readonly Regex EmailRegex = new Regex(@"(?("")("".+?(?<!\\)""@)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])@))(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))", RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(500)); 

    // ------------------------------------------------------------------------------------------- 
    /// <summary> 
    /// The regex to detect the phone numbers from the raw message 
    /// </summary> 
    private static readonly Regex PhoneRegex = new Regex(@"\+?[\d\-\(\)\. ]{5,}", RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(250)); 

    // ------------------------------------------------------------------------------------------- 
    /// <summary> 
    /// The default prefix to use to convert a relative URI to an absolute URI 
    /// The Windows RunTime is only working with absolute URI 
    /// </summary> 
    private const string RelativeUriDefaultPrefix = "http://"; 


    // ------------------------------------------------------------------------------------------- 
    /// <summary> 
    /// The dependency property to generate an interactive text in a text block. 
    /// When setting this property, we will parse the value and transform the hyperlink or the email address to interactive fields that the user can interact width. 
    /// The raw text will be parsed and convert to a collection of inlines. 
    /// </summary> 
    public static readonly DependencyProperty InteractiveTextProperty = DependencyProperty.RegisterAttached("InteractiveText", typeof(string), typeof(TextBlock), new PropertyMetadata(null, OnInteractiveTextChanged)); 

    // ------------------------------------------------------------------------------------------- 
    /// <summary> 
    /// The event callback for the interactive text changed event 
    /// We will parse the raw text and generate the inlines that will wrap the interactive items (URL...) 
    /// </summary> 
    /// <param name="d">the object which has raised the event</param> 
    /// <param name="e">the change information</param> 
    private static void OnInteractiveTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var textBlock = d as Windows.UI.Xaml.Controls.TextBlock; 
     if(textBlock == null) return; 

     // we remove all the inlines 
     textBlock.Inlines.Clear(); 

     // if we have no data, we do not need to go further 
     var rawText = e.NewValue as string; 
     if(string.IsNullOrEmpty(rawText)) return; 


     var lastPosition = 0; 
     var matches   = new Match[3]; 
     do 
     { 
      matches[0] = UrlRegex.Match(rawText, lastPosition); 
      matches[1] = EmailRegex.Match(rawText, lastPosition); 
      matches[2] = PhoneRegex.Match(rawText, lastPosition); 

      var firstMatch = matches.Where(x => x.Success).OrderBy(x => x.Index).FirstOrDefault(); 
      if(firstMatch == matches[0]) 
      { 
       // the first match is an URL 
       CreateRunElement(textBlock, rawText, lastPosition, firstMatch.Index); 
       lastPosition = CreateUrlElement(textBlock, firstMatch); 
      } 
      else if(firstMatch == matches[1]) 
      { 
       // the first match is an email 
       CreateRunElement(textBlock, rawText, lastPosition, firstMatch.Index); 
       lastPosition = CreateContactElement(textBlock, firstMatch, null); 
      } 
      else if(firstMatch == matches[2]) 
      { 
       // the first match is a phonenumber 
       CreateRunElement(textBlock, rawText, lastPosition, firstMatch.Index); 
       lastPosition = CreateContactElement(textBlock, null, firstMatch); 
      } 
      else 
      { 
       // no match, we add the whole text 
       textBlock.Inlines.Add(new Run { Text = rawText.Substring(lastPosition) }); 
       lastPosition = rawText.Length; 
      } 
     } 
     while(lastPosition < rawText.Length); 
    } 

    // ------------------------------------------------------------------------------------------- 
    /// <summary> 
    /// This method will extract a fragment of the raw text string, create a Run element with the fragment and 
    /// add it to the textblock inlines collection 
    /// </summary> 
    /// <param name="textBlock">the textblock where to add the run element</param> 
    /// <param name="rawText">the raw text where the fragment will be extracted</param> 
    /// <param name="startPosition">the start position to extract the fragment</param> 
    /// <param name="endPosition">the end position to extract the fragment</param> 
    private static void CreateRunElement(Windows.UI.Xaml.Controls.TextBlock textBlock, string rawText, int startPosition, int endPosition) 
    { 
     var fragment = rawText.Substring(startPosition, endPosition - startPosition); 
     textBlock.Inlines.Add(new Run { Text = fragment }); 
    } 

    // ------------------------------------------------------------------------------------------- 
    /// <summary> 
    /// Create an URL element with the provided match result from the URL regex 
    /// It will create the Hyperlink element that will contain the URL and add it to the provided textblock 
    /// </summary> 
    /// <param name="textBlock">the textblock where to add the hyperlink</param> 
    /// <param name="urlMatch">the match for the URL to use to create the hyperlink element</param> 
    /// <returns>the newest position on the source string for the parsing</returns> 
    private static int CreateUrlElement(Windows.UI.Xaml.Controls.TextBlock textBlock, Match urlMatch) 
    { 
     Uri targetUri; 
     if(Uri.TryCreate(urlMatch.Value, UriKind.RelativeOrAbsolute, out targetUri)) 
     { 
      var link   = new Hyperlink(); 
      link.Inlines.Add(new Run { Text= urlMatch.Value }); 

      if(targetUri.IsAbsoluteUri) 
       link.NavigateUri = targetUri; 
      else 
       link.NavigateUri = new Uri(RelativeUriDefaultPrefix + targetUri.OriginalString); 


      textBlock.Inlines.Add(link); 
     } 
     else 
     { 
      textBlock.Inlines.Add(new Run { Text= urlMatch.Value }); 
     } 

     return urlMatch.Index + urlMatch.Length; 
    } 

    // ------------------------------------------------------------------------------------------- 
    /// <summary> 
    /// Create a hyperlink element with the provided match result from the regex that will open the contact application 
    /// with the provided contact information (it should be a phone number or an email address 
    /// This is used only if the email address/phone number is not prefixed with the mailto:/tel: scheme 
    /// It will create the Hyperlink element that will contain the email/phone number hyperlink and add it to the provided textblock. 
    /// Clicking on the link will open the contact application 
    /// </summary> 
    /// <param name="textBlock">the textblock where to add the hyperlink</param> 
    /// <param name="emailMatch">the match for the email to use to create the hyperlink element. Set to null if not available but at least one of emailMatch and phoneMatch must be not null.</param> 
    /// <param name="phoneMatch">the match for the phone number to create the hyperlink element. Set to null if not available but at least one of emailMatch and phoneMatch must be not null.</param> 
    /// <returns>the newest position on the source string for the parsing</returns> 
    private static int CreateContactElement(Windows.UI.Xaml.Controls.TextBlock textBlock, Match emailMatch, Match phoneMatch) 
    { 
     var currentMatch = emailMatch ?? phoneMatch; 

     var link   = new Hyperlink(); 
     link.Inlines.Add(new Run { Text= currentMatch.Value }); 
     link.Click   += (s, a) => 
     { 
      var contact  = new Contact(); 
      if(emailMatch != null) contact.Emails.Add(new ContactEmail { Address = emailMatch.Value }); 
      if(phoneMatch != null) contact.Phones.Add(new ContactPhone { Number = phoneMatch.Value.StripNonDigitsCharacters() }); 

      ContactManager.ShowFullContactCard(contact, new FullContactCardOptions()); 
     }; 

     textBlock.Inlines.Add(link); 
     return currentMatch.Index + currentMatch.Length; 
    } 

    // ------------------------------------------------------------------------------------------- 
    /// <summary> 
    /// Return the InteractiveText value on the provided object 
    /// </summary> 
    /// <param name="obj">the object to query</param> 
    /// <returns>the InteractiveText value</returns> 
    public static string GetInteractiveText(DependencyObject obj) 
    { 
     return (string) obj.GetValue(InteractiveTextProperty); 
    } 

    // ------------------------------------------------------------------------------------------- 
    /// <summary> 
    /// SEt the InteractiveText value on the provided object 
    /// </summary> 
    /// <param name="obj">the object to query</param> 
    /// <param name="value">the value to set</param> 
    public static void SetInteractiveText(DependencyObject obj, string value) 
    { 
     obj.SetValue(InteractiveTextProperty, value); 
    } 
+0

おかげで、私はそれで問題があるようです。 "Line:38 Position:20" " –

+0

" MyProject.TextBlockExtensions.InteractiveText 'プロパティに割り当てるのに失敗しました。詳細はなく、難しいです。何が間違っているかを見る。エラーメッセージによれば、コントロールに型の問題がある可能性があります。プロパティはTextBoxにのみバインドできます。それを別のものにバインドしようとすると、この種のエラーが発生します。詳細については、この質問を参照してください:http://stackoverflow.com/questions/17971195/xamlparseexception-failed-to-assign-to-property-binding-not-working-with-attach。また、ここから便利な情報を見つけることができます:http://stackoverflow.com/questions/5832208/wpf-attached-property-data-binding役に立つと思っています。 – Vincent

+0

Vincentに感謝します。間違いを発見しました。私の拡張クラスは公開されていませんでした。今はうまくいくようです。 –

関連する問題