2009-10-14 3 views

답변

6

개별 단어를 묶는 것은 실제로 더 많은 인라인 요소를 만드는 것과 관련되어 있으므로 문자열을 TextBlock의 텍스트에 바인딩하고 수행 할 수는 없습니다.

내가 과거에해온 것은 내가 바인딩하는 사용자 정의 속성이있는 TextBlock의 하위 클래스를 만든 것입니다. 이 속성이 바인딩되면 기본 TextBlock의 인라인을 지운 다음 일반 문자열, 굵게, 하이퍼 링크 등을 만드는 새 문자열 값을 구문 분석하는 알고리즘을 사용합니다.

실험용 Twitter 클라이언트에 대해 작성한 몇 가지 샘플 코드는 다음과 같습니다 URL, 이메일 및 @ 패턴을 탐지하고 그들에 대한 하이퍼 링크를 생성합니다. 일반 텍스트는 보통 실행으로 인라인됩니다.

[ContentProperty("StatusText")] 
public sealed class StatusTextBlock : TextBlock 
{ 
    #region Fields 

    public static readonly DependencyProperty StatusTextProperty = DependencyProperty.Register(
                        "StatusText", 
                          typeof(string), 
                        typeof(StatusTextBlock), 
                        new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.None, StatusTextBlock.StatusTextPropertyChangedCallback, null)); 
    private static readonly Regex UriMatchingRegex = new Regex(@"(?<url>[a-zA-Z]+:\/\/[a-zA-Z0-9]+([\-\.]{1}[a-zA-Z0-9]+)*\.[a-zA-Z]{2,5}(:[0-9]{1,5})?([a-zA-Z0-9_\-\.\~\%\+\?\=\&\;\|/]*)?)|(?<emailAddress>[^\s][email protected][a-zA-Z0-9]+([\-\.]{1}[a-zA-Z0-9]+)*\.[a-zA-Z]{2,5})|(?<toTwitterScreenName>\@[a-zA-Z0-9\-_]+)", RegexOptions.Compiled); 

    #endregion 

    #region Constructors 

    public StatusTextBlock() 
    { 
    } 

    #endregion 

    #region Type specific properties 

    public string StatusText 
    { 
     get 
     { 
      return (string)this.GetValue(StatusTextBlock.StatusTextProperty); 
     } 

     set 
     { 
      this.SetValue(StatusTextBlock.StatusTextProperty, value); 
     } 
    } 

    #endregion 

    #region Helper methods 

    internal static IEnumerable<Inline> GenerateInlinesFromRawEntryText(string entryText) 
    { 
     int startIndex = 0; 
     Match match = StatusTextBlock.UriMatchingRegex.Match(entryText); 

     while(match.Success) 
     { 
      if(startIndex != match.Index) 
      { 
       yield return new Run(StatusTextBlock.DecodeStatusEntryText(entryText.Substring(startIndex, match.Index - startIndex))); 
      } 

      Hyperlink hyperLink = new Hyperlink(new Run(match.Value)); 

      string uri = match.Value; 

      if(match.Groups["emailAddress"].Success) 
      { 
       uri = "mailto:" + uri; 
      } 
      else if(match.Groups["toTwitterScreenName"].Success) 
      { 
       uri = "http://twitter.com/" + uri.Substring(1); 
      } 

      hyperLink.NavigateUri = new Uri(uri); 

      yield return hyperLink; 

      startIndex = match.Index + match.Length; 

      match = match.NextMatch(); 
     } 

     if(startIndex != entryText.Length) 
     { 
      yield return new Run(StatusTextBlock.DecodeStatusEntryText(entryText.Substring(startIndex))); 
     } 
    } 

    internal static string DecodeStatusEntryText(string text) 
    { 
     return text.Replace("&gt;", ">").Replace("&lt;", "<"); 
    } 

    private static void StatusTextPropertyChangedCallback(DependencyObject target, DependencyPropertyChangedEventArgs eventArgs) 
    { 
     StatusTextBlock targetStatusEntryTextBlock = (StatusTextBlock)target; 

     targetStatusEntryTextBlock.Inlines.Clear(); 

     string newValue = eventArgs.NewValue as string; 

     if(newValue != null) 
     { 
      targetStatusEntryTextBlock.Inlines.AddRange(StatusTextBlock.GenerateInlinesFromRawEntryText(newValue)); 
     } 
    } 

    #endregion 
} 
+0

이 방법으로 텍스트의 색상을 다르게 지정할 수 있습니까? –

+0

물론, Run 인스턴스의 Foreground 속성을 원하는 브러시로 설정하면됩니다. –

+0

같은 종류의 텍스트 상자를 시도한 적있으세요? 텍스트 상자에는 인라인 속성이 없으므로 텍스트 상자를 사용해야합니다. –

관련 문제