2012-05-22 81 views
2

我有一個WPF應用程序TextBlock的,我想在那裏向用戶顯示類似的消息:嵌入式鏈接

Retrygo back.

我可以通過執行實現這一目標:

<TextBlock> 
    <Hyperlink Command="{Binding RetryCommand}"> 
     <Run Text="Retry" /> 
    </Hyperlink> 
    <Run Text=" or " /> 
    <Hyperlink Command="{Binding GoBackCommand}"> 
     <Run Text="go back." /> 
    </Hyperlink> 
</TextBlock> 

但是,這個解決方案對本地化並不是很友好,在句子在本地化過程中需要重新排列的情況下特別成問題。我更願意能夠在resx文件中指定類似"[Retry]({0}) or [go back.]({1})."的內容,並將超鏈接動態插入到本地化字符串中。有沒有一種乾淨而簡單的方法可以做到這一點?

在另一個應用程序中,我們使用了一個令人驚訝的複雜解決方案,涉及擴展TextBlock類和動態構建Inline屬性,但它似乎是很多代碼,應該是一個常見問題。

相關的問題:Is adding strings with placeholders (`{0}`) into resources a good idea?How to embed links in localized text

回答

1

所以我想一個解決方案將是一個自定義的控制。但是,我能夠使用IMultiValueConverter完成工作。

public class TextBlockFormatToHyperlinkConverter : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     if (values.Length >= 3) 
     { 
      var tblk = values[0] as TextBlock; 
      var format = values[1] as string; 
      var tokens = Tokenizer.ParseTokens(format); 
      int hyperLinkIndex = 0; 
      for (int i = 2; i < values.Length; i++) 
      { 
       var token = tokens.FirstOrDefault((p) => string.Equals(p.Value as string, "{" + hyperLinkIndex + "}")); 
       if (token != null) 
       { 
        token.Value = values[i]; 
       } 
       hyperLinkIndex++; 
      } 

      tblk.Inlines.Clear(); 
      foreach (var token in tokens) 
      { 
       if (token.Value is Hyperlink) 
        tblk.Inlines.Add((Hyperlink)token.Value); 
       else 
        tblk.Inlines.Add(new Run(token.Value as string)); 
      } 

      return tblk; 
     } 
     return null; 
    } 

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 

    private class Token 
    { 
     public object Value { get; set; } 
     public Token(object value) 
     { 
      Value = value; 
     } 
    } 
    private class HyperlinkToken : Token 
    { 
     public HyperlinkToken(object value) : base(value) { } 
    } 

    private static class Tokenizer 
    { 
     public static List<Token> ParseTokens(string format) 
     { 
      var tokens = new List<Token>(); 
      var strings = Regex.Split(format, @"({\d+})"); 
      foreach (var str in strings) 
      { 
       if (Regex.IsMatch(str, @"({\d+})")) 
       { 
        tokens.Add(new HyperlinkToken(str)); 
       } 
       else 
       { 
        tokens.Add(new Token(str)); 
       } 
      } 
      return tokens; 
     } 
    } 
} 

然後在XAML我用這樣的:

<TextBlock x:Name="tblk_LogFileLink" TextWrapping="Wrap"> 
    <TextBlock.Tag> 
     <MultiBinding Converter="{StaticResource TextBlockFormatToHyperlinkConverter}"> 
      <Binding x:Name="textblock" ElementName="tblk_LogFileLink"/> 
      <Binding x:Name="formatString" Source="Click to open the {0}."/> 
      <Binding x:Name="firstHyperlink"> 
       <Binding.Source> 
        <Hyperlink NavigateUri="{Binding LogPath}"> 
         <Run Text="{x:Static localization:Resources.LBL_LOG_FILE}"/> 
        </Hyperlink> 
       </Binding.Source> 
      </Binding> 
     </MultiBinding> 
    </TextBlock.Tag> 
</TextBlock> 

如果需要更多的字符串格式你可以添加一些超鏈接到MultiBinding。

這使我可以本地化整個字符串,同時仍然提供超鏈接文本。