繁体   English   中英

如何使格式化的TextBlock宽度数据绑定可本地化?

[英]How can I make a formatted TextBlock width data binding localizable?

在我的WPF应用程序中,我想显示如下所示的内容:

用户Bob已于22:17退出。

“Bob”和“22:17”是数据绑定值。

显而易见的方法是使用带有多个TextBlockStackPanel ,其中一些绑定数据:

<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> 但这当然不起作用。

这必须是一个常见的问题,对此有什么正确的解决方案?

我看到的问题是你想要一个String但是在整个String有不同的UI存在。

一种选择可能是忽略对粗体的需要,只需将单个String放在Resources.resx文件中即可。 然后,将在TextBlock绑定的属性中引用该String ,并根据需要返回值; {0}和{1}适用的地方。

另一个选项可能是返回一组要在TextBlock保存的Run值。 你不能绑定到3.5中的Run out,但我相信你可以在4。

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

最后一个选项可以在这里找到并涉及为Run概念创建一个更动态的方法,允许您绑定您的值,然后将它们绑定回String

我之前从未尝试过这样的事情,但是如果我不得不尝试使用一个转换器来接受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
    }
}

这个问题不可能只有一个解决方案,因为它有很多不同的方式可以表现出来,并且有很多不同的方法可以解决它。

如果您是Microsoft,解决方案是将所有模板放在资源字典中,创建一个可以使用Expression Blend呈现它们的项目,然后让您的翻译人员使用Blend(可能还有可以帮助他们使用它的人) )翻译资源字典中的文本,重新排序模板中按字顺序存在惯用差异的元素。 这当然是最昂贵的解决方案,但它的优势在于,在翻译UI的同时解决了格式化问题(比如有人忘记了法语文本占用的空间比英文文本多20%)。 它还具有以下优点:它处理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>

令人惊讶的是,该标记格式也可以在Web浏览器中查看,因此可以使用各种各样的工具和校对进行编辑,而无需使用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>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM