Как сделать локализованную привязку форматированной ширины данных TextBlock? - PullRequest
13 голосов
/ 02 декабря 2010

В моем приложении WPF я бы хотел отобразить что-то похожее на это:

Пользователь Боб вышел из системы при 22: 17 .

Где «Боб» и «22:17» являются привязанными к данным значениями.

Очевидный способ сделать это - использовать StackPanel с несколькими TextBlock дочерними элементами, некоторые из которых связаны с данными:

<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>. Но это не работает, конечно.

Это должно быть распространенной проблемой, какое правильное решение для этого?

Ответы [ 3 ]

12 голосов
/ 02 декабря 2010

Проблема, которую я вижу, заключается в том, что вам нужен один String, но с другим присутствием пользовательского интерфейса в String.

Один из вариантов может заключаться в том, чтобы отменить необходимость в выделении жирным шрифтом и просто поместить один String в файл Resources.resx. Затем на String будет ссылаться свойство, с которым связан TextBlock, возвращая значения по мере необходимости; {0} и {1}, где это применимо.

Другим вариантом может быть возврат набора Run значений, которые должны храниться в TextBlock. Вы не можете связать с 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>

Последний вариант можно найти здесь и включает в себя создание более динамичного подхода к концепции Run, позволяющего вам связать свои значения и затем связать их обратно с String.

4 голосов
/ 02 декабря 2010

Я никогда не пытался сделать что-то подобное раньше, но если бы мне было нужно, я бы, вероятно, попытался бы использовать конвертер, который берет 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
    }
}
0 голосов
/ 02 декабря 2010

Маловероятно, что будет одно решение этой проблемы, потому что есть много разных способов, которыми она может проявиться, и есть так много разных способов ее решения.

Если вы Microsoft, решение состоит в том, чтобы поместить все ваши шаблоны в словарь ресурсов, создать проект, который может использовать Expression Blend для их представления, а затем заставить ваших переводчиков работать с Blend (и, возможно, с кем-то, кто может помочь они используют его), чтобы перевести текст в словарь ресурсов, переупорядочив элементы в шаблоне, где есть идиоматические различия в порядке слов. Это, конечно, самое дорогое решение, но оно имеет то преимущество, что позволяет решить проблемы с форматированием (например, кто-то забыл, что текст на французском языке занимает примерно на 20% больше места, чем текст на английском языке), одновременно с переводом пользовательского интерфейса. Он также имеет то преимущество, что обрабатывает каждую презентацию текста в пользовательском интерфейсе, а не только презентации, которые создаются путем объединения вместе текстовых блоков.

Если вам действительно нужно только исправить стеки текстовых блоков, вы можете создать простое 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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...