2012-05-22 93 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。

这使我可以本地化整个字符串,同时仍然提供超链接文本。