2010-12-02 63 views
13

在我的WPF應用程序,我想展示的東西,看起來像這樣:如何使格式化的TextBlock寬度數據綁定可本地化?

用戶鮑勃已在22:17註銷。

其中「Bob」和「22:17」是數據綁定值。

最明顯的方法,這樣做將是使用StackPanelTextBlock孩子,他們中的一些數據綁定:

<StackPanel Orientation="Horizontal"> 
    <TextBlock Text="The user"/> 
    <TextBlock Text="{Binding Path=Username}" TextBlock.FontWeight="Bold" /> 
    <TextBlock Text="has logged off at"/> 
    <TextBlock Text="{Binding Path=LogoffTime}" TextBlock.FontWeight="Bold" /> 
</StackPanel/> 

這工作,但它的醜陋。該程序應該被本地化爲不同的語言,並且爲「用戶」和「已註銷」分隔字符串是本地化災難的接受者。

理想情況下,我願做這樣的事情:

<TextBlock> 
    <TextBlock.Text> 
     <MultiBinding StringFormat="{}The user <Bold>{0}</Bold> has logged off at <Bold>{1}</Bold>"> 
      <Binding Path="Username" /> 
      <Binding Path="LogoffTime" /> 
     </MultiBinding> 
</TextBlock> 

因此翻譯將看到一個完整的句子The user <Bold>{0}</Bold> has logged off at <Bold>{1}</Bold>。但是,這當然不起作用。

這是一個常見問題,對此有什麼正確的解決方案?

回答

4

我從來沒有嘗試過做這樣的事情,但如果我不得不我可能會嘗試使用一個轉換器,是以MultiBinding,打破它,並返回一個StackPanel件的

例如,結合會是這樣的:

<Label> 
    <Label.Content> 
      <MultiBinding Converter={StaticResource TextWithBoldParametersConverter}> 
       <Binding Source="The user {0} has logged off at {1}" /> 
       <Binding Path="Username" /> 
       <Binding Path="LogoffTime" /> 
      </MultiBinding> 
    </Label.Content> 
</Label> 

和轉換器會做類似

public class TextWithBoldParametersConverter: IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 
    { 
     // Create a StackPanel to hold the content 
     // Set StackPanel's Orientation to Horizontal 

     // Take values[0] and split it by the {X} tags 

     // Go through array of values parts and create a TextBlock object for each part 
      // If the part is an {X} piece, use values[X+1] for Text and make TextBlock bold 
      // Add TextBlock to StackPanel 

     // return StackPanel 
    } 
} 
12

我看到的問題是,您希望單個StringString之間具有不同的UI存在。

一個選項可以是忽略粗體的需要,只需在Resources.resx文件中放置單個String即可。然後String將在TextBlock所綁定的屬性中被引用,並根據需要返回值; {0}和{1}(如適用)。

另一種選擇可能是返回一組要在TextBlock內保留的一組Run值。你不能綁定到Run開箱3.5,但是我相信你可以在4

  <TextBlock> 
        <Run Text="The user "/><Run FontWeight="Bold" Text="{Binding User}"/><Run Text="has logged at "/><Run FontWeight="Bold" Text="{Binding LogoffTime}"/> 
      </TextBlock> 

最後的選擇,可以發現here和涉及創建一個更加動態的方法來Run概念,讓您綁定您的值,然後將其綁回String

0

有不太可能是單一的解決這個問題因爲它可以表現出很多不同的方式,並且有很多不同的方式來解決它。

如果您是微軟,解決方案是將所有模板放入資源字典中,創建一個可以使用Expression Blend呈現它們的項目,然後讓您的翻譯人員使用Blend(可能有人可以幫助他們使用它)來翻譯資源字典中的文本,重新排序模板中字元順序存在慣用差異的元素。這當然是最昂貴的解決方案,但它具有獲取格式問題的優勢(比如有人忘記了法文文本比英文文本佔用了大約20%的空間)並且在翻譯UI的同時解決了這個問題。它還具有處理UI中每個文本呈現的優點,而不僅僅是通過將文本塊堆疊在一起而創建的呈現。

如果您確實只需要修復文本塊的堆棧,則可以創建標記文本的簡單XML表示形式,並使用XSLT從該格式的文件創建XAML。舉例來說,像這樣:

<div id="LogoutTime" class="StackPanel"> 
    The user 
    <strong><span class="User">Bob</span><strong> 
    logged out at 
    <strong><span class="Time">22:17</span></strong> 
    . 
</div> 

通過一個驚人的巧合,該標記的格式是一個,也可以在網頁瀏覽器中查看,因此它可以用一個非常廣泛的工具進行編輯,而無需使用校對,比如說Expression Blend。並且將其翻譯回XAML相對簡單:

<xsl:template match="div[@class='StackPanel']"> 
    <DataTemplate x:Key="{@id}"> 
     <StackPanel Orientation="Horizontal"> 
     <xsl:apply-templates select="node()"/> 
     </StackPanel> 
    </DataTemplate> 
</xsl:template> 

<xsl:template match="div/text()"> 
    <TextBlock Text="{.}"/> 
</xsl:template> 

<xsl:template match="strong/span"> 
    <TextBlock FontWeight="Bold"> 
     <xsl:attribute name="Text"> 
     <xsl:text>{Binding </xsl:text> 
     <xsl:value-of select="@class"/> 
     <xsl:text>}</xsl:text> 
     </xsl:attribute> 
    </TextBlock> 
</xsl:template> 
相關問題