Поделиться через


Обзор двунаправленных возможностей в WPF

В отличие от любой другой платформы разработки, WPF имеет множество функций, которые поддерживают быстрое развитие двунаправленного содержимого, например смешанные слева направо и справа налево данные в том же документе. В то же время WPF создает отличный интерфейс для пользователей, которым требуются двунаправленные функции, такие как арабские и ивритовые пользователи.

В следующих разделах объясняется множество двунаправленных функций вместе с примерами, которые иллюстрируют, как добиться оптимального отображения двунаправленного содержимого. Большинство примеров используют XAML, хотя вы можете легко применить основные понятия к коду C# или Microsoft Visual Basic.

FlowDirection

Базовое свойство, определяющее направление потока контента в приложении WPF, это FlowDirection. Это свойство можно задать для одного из двух значений перечисления, LeftToRight или RightToLeft. Свойство доступно для всех элементов WPF, наследующих от FrameworkElement.

В следующих примерах задано направление потока элемента TextBox.

Направление потока слева направо

<TextBlock Background="DarkBlue" Foreground="LightBlue" 
   FontSize="20" FlowDirection="LeftToRight">
        This is a left-to-right TextBlock
</TextBlock>

Направление потока справа налево

<TextBlock Background="LightBlue" Foreground="DarkBlue"
   FontSize="20" FlowDirection="RightToLeft">
        This is a right-to-left TextBlock
</TextBlock>

На следующем рисунке показано, как отрисовывается предыдущий код.

Рисунок, иллюстрирующий различные направления потока.

Элемент в дереве пользовательского интерфейса наследует FlowDirection от контейнера. В следующем примере TextBlock находится внутри Grid, который находится в объекте Window. Настройка FlowDirection для Window подразумевает также настройку для Grid и TextBlock.

В следующем примере показан параметр FlowDirection.

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="FlowDirectionApp.Window1"
    Title="BidiFeatures" Height="200" Width="700" 
    FlowDirection="RightToLeft">
     
    <Grid>
      <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
      </Grid.ColumnDefinitions>
      <TextBlock Grid.Column="0" >
          This is a right-to-left TextBlock
      </TextBlock>

      <TextBlock Grid.Column="1" FlowDirection="LeftToRight">
          This is a left-to-right TextBlock
      </TextBlock>
    </Grid>
</Window>

Верхний уровень Window имеет RightToLeftFlowDirection, поэтому все элементы, содержащиеся в нем, также наследуют одинаковые FlowDirection. Чтобы элемент мог переопределить указанный FlowDirection, необходимо добавление явного изменения направления, как это сделано во втором TextBlock в предыдущем примере, где происходит изменение на LeftToRight. Если не FlowDirection определено, применяется значение по умолчанию LeftToRight .

На следующем рисунке показаны выходные данные предыдущего примера:

Рисунок, демонстрирующий явное изменение направления потока.

Потоковый документ

Многие платформы разработки, такие как HTML, Win32 и Java, обеспечивают специальную поддержку двунаправленной разработки контента. Языки разметки, такие как HTML, предоставляют авторам контента необходимую разметку с возможностью отображения текста в любом требуемом направлении, например, тег HTML 4.0 "dir", который принимает значения "rtl" или "ltr". Этот тег аналогичен FlowDirection свойству, но FlowDirection свойство работает более сложным способом макета текстового содержимого и может использоваться для содержимого, отличного от текста.

В элементе пользовательского интерфейса, который может размещать сочетание текста, таблиц, изображений и других элементов. Примеры в следующих разделах используют этот элемент.

Добавление текста в FlowDocument можно сделать несколькими способами. Простой способ сделать это — это Paragraph элемент уровня блока, используемый для группировки содержимого, например текста. Чтобы добавить текст к элементам строчного уровня, используются Span и Run. Span — это элемент содержимого потока встроенного уровня, используемый для группировки других встроенных элементов, а Run элемент содержимого потока встроенного уровня, предназначенный для хранения неформатированного текста. Span может содержать несколько Run элементов.

Первый пример документа содержит документ с несколькими именами сетевых общих файлов; например \\server1\folder\file.ext. Независимо от того, есть ли у вас эта сетевая ссылка на арабском или английском документах, она всегда должна отображаться таким же образом. На следующем графике демонстрируется использование элемента Span и показана ссылка в арабском RightToLeft документе.

Рисунок, иллюстрирующий использование элемента Span.

Так как текст обозначен как RightToLeft, все специальные символы, такие как "\", разделяют текст справа налево. Это приводит к тому, что ссылка не отображается в правильном порядке, поэтому для решения проблемы текст должен быть интегрирован так, чтобы сохранить отдельные потоки Run и LeftToRight. Вместо того чтобы иметь отдельный Run язык, лучший способ решить проблему заключается в внедрении менее часто используемого английского текста в более крупный арабский Spanязык.

На следующем рисунке показано, как использовать элемент Run, внедренный в элемент Span:

Рисунок, иллюстрирующий элемент Run, внедренный в элемент Span.

В следующем примере показано использование Run и Span элементы в документах.

<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    FlowDirection="RightToLeft">

  <FlowDocument>
    <Paragraph>
      <Span FlowDirection="RightToLeft" >
        ستجد الملف هنا:
        <Run FlowDirection="LeftToRight">
           \\server1\filename\filename1.txt</Run>
        ثم باقى النص!
      </Span>
    </Paragraph>
  </FlowDocument>
</Page>

Элементы диапазона

Элемент Span работает в качестве разделителя границ между текстами с различными направлениями потока. Даже Span элементы с одинаковым направлением потока считаются различными двунаправленными областями, что означает, что Span элементы упорядочены в контейнере FlowDirection, только содержимое в Span элементе следует за FlowDirectionSpanэлементом.

На следующем рисунке показано направление потока нескольких TextBlock элементов.

Рисунок, демонстрирующий текстовые блоки с различными направлениями потока.

В следующем примере показано, как использовать Span элементы и Run элементы для получения результатов, показанных на предыдущем рисунке.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
  <StackPanel >

    <TextBlock FontSize="20" FlowDirection="RightToLeft">
      <Run FlowDirection="LeftToRight">العالم</Run>
      <Run FlowDirection="LeftToRight" Foreground="Red" >فى سلام</Run>
    </TextBlock>

    <TextBlock FontSize="20" FlowDirection="LeftToRight">
      <Run FlowDirection="RightToLeft">العالم</Run>
      <Run FlowDirection="RightToLeft" Foreground="Red" >فى سلام</Run>
    </TextBlock>

    <TextBlock FontSize="20" Foreground="Blue">العالم فى سلام</TextBlock>

    <Separator/>

    <TextBlock FontSize="20" FlowDirection="RightToLeft">
      <Span Foreground="Red" FlowDirection="LeftToRight">Hello</Span>
      <Span FlowDirection="LeftToRight">World</Span>
    </TextBlock>

    <TextBlock FontSize="20" FlowDirection="LeftToRight">
      <Span Foreground="Red" FlowDirection="RightToLeft">Hello</Span>
      <Span FlowDirection="RightToLeft">World</Span>
    </TextBlock>

    <TextBlock FontSize="20" Foreground="Blue">Hello World</TextBlock>

  </StackPanel>

</Page>

TextBlock В примере Span элементы выкладываются в соответствии со FlowDirection своими родителями, но текст в каждом Span элементе передается в соответствии с собственнымиFlowDirection. Это применимо к латинице и арабскому языку или любому другому языку.

Добавление xml:lang

На следующем рисунке показан другой пример использования чисел и арифметических выражений, таких как "200.0+21.4=221.4". Обратите внимание, что задано только это FlowDirection значение.

Рисунок, отображающий числа, использующие только FlowDirection.

Пользователи этого приложения будут разочарованы выходными данными, несмотря FlowDirection на то, что правильные цифры не формируются как арабские цифры должны быть сформированы.

Элементы XAML могут включать xml-атрибут (xml:lang), определяющий язык каждого элемента. XAML также поддерживает принцип языка XML, в xml:lang котором значения, применяемые к родительским элементам дерева, используются дочерними элементами. В предыдущем примере, поскольку язык не определен для Run элемента или любого из его элементов верхнего уровня, используется xml:lang значение по умолчанию en-US для XAML. Внутренний алгоритм формирования чисел Windows Presentation Foundation (WPF) выбирает числа на соответствующем языке — в данном случае на английском языке. Для правильной отрисовки xml:lang арабских чисел необходимо задать.

На следующем рисунке показан пример с xml:lang добавленным.

Рисунок, иллюстрирующий арабские цифры, которые текают справа налево.

Следующий пример добавляется xml:lang в приложение.

<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    FlowDirection="RightToLeft">
      <FlowDocument>
         <Paragraph>
            <Span FlowDirection="RightToLeft" Language="ar-SA">
              العملية الحسابية: "200.0+21.4=221.4"
            </Span>
         </Paragraph>
      </FlowDocument>
</Page>

Помните, что многие языки имеют разные xml:lang значения в зависимости от целевого региона, например, "ar-SA" и "ar-EG" представляют два варианта арабского языка. В предыдущих примерах показано, что необходимо определить как значения xml:lang, так и FlowDirection.

НаправлениеПотока с нетекстовыми элементами

FlowDirection определяет не только поток текста в текстовом элементе, но и направление потока почти каждого другого элемента пользовательского интерфейса. На следующем рисунке показан ToolBar, который использует горизонтальную LinearGradientBrush для рисования фона с градиентом слева направо.

Рисунок, показывающий панель инструментов с градиентом слева направо.

После установки FlowDirection на RightToLeft, не только ToolBar кнопки упорядочиваются справа налево, но даже LinearGradientBrush перестраивает свои смещения, чтобы были направлены справа налево.

На следующем рисунке показано перестройка LinearGradientBrush.

Рисунок, показывающий панель инструментов с градиентом справа налево.

В следующем примере нарисовывается RightToLeftToolBar. (Чтобы нарисовать его слева направо, удалите атрибут FlowDirection на ToolBar.

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  
  <ToolBar FlowDirection="RightToLeft" Height="50" DockPanel.Dock="Top">
    <ToolBar.Background>
      <LinearGradientBrush StartPoint="0,0.5" EndPoint="1,1">
        <LinearGradientBrush.GradientStops>
          <GradientStop Color="DarkRed" Offset="0" />
          <GradientStop Color="DarkBlue" Offset="0.3" />
          <GradientStop Color="LightBlue" Offset="0.6" />
          <GradientStop Color="White" Offset="1" />
        </LinearGradientBrush.GradientStops>
      </LinearGradientBrush>
    </ToolBar.Background>

    <Button FontSize="12" Foreground="White">Button1</Button>
    <Rectangle Width="20"/>
    <Button FontSize="12" Foreground="White">Button2</Button>
    <Rectangle Width="20"/>
    <Button FontSize="12" Foreground="White">Button3</Button>
    <Rectangle Width="20"/>
    <Button FontSize="12" Foreground="White">Button4</Button>
    <Rectangle Width="20"/>
  </ToolBar>
</Page>

FlowDirection: Исключения

Существует несколько случаев, когда FlowDirection не ведет себя так, как ожидалось. В этом разделе рассматриваются два из этих исключений.

Изображение

Image — это элемент управления, отображающий изображение. В XAML его можно использовать со свойством Source , определяющим универсальный идентификатор ресурса (URI) отображаемого Image объекта.

В отличие от других элементов пользовательского интерфейса, объект Image не наследует FlowDirection от контейнера. Однако, если для FlowDirection явно установлено значение RightToLeft, Image отображается перевёрнутым по горизонтали. Это реализовано как удобная функция для разработчиков двунаправленного содержимого; так как в некоторых случаях горизонтальное переворачивание изображения создает нужный эффект.

На следующем рисунке показан перевернутый элемент Image.

Рисунок, иллюстрирующий перевернутое изображение.

В следующем примере показано, что Image не удается наследовать FlowDirection от StackPanel содержащего его фрагмента.

Замечание

Для выполнения этого примера необходимо иметь файл с именемms_logo.jpg на диске C:\ .

<StackPanel 
  xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' 
  FlowDirection="RightToLeft">

  <Image Source="file://c:/ms_logo.jpg" 
         Width="147" Height="50"/>
  <Separator Height="10"/>
  <Image Source="file://c:/ms_logo.jpg" 
         Width="147" Height="50" FlowDirection="LeftToRight" />
  <Separator Height="10"/>
  <Image Source="file://c:/ms_logo.jpg" 
         Width="147" Height="50" FlowDirection="RightToLeft"/>
</StackPanel>

Замечание

В файлы скачивания входит файлms_logo.jpg . В коде предполагается, что файл .jpg находится не внутри проекта, а где-то на диске C:\. Необходимо скопировать .jpg из файлов проекта на диск C:\ или изменить код, чтобы найти файл внутри проекта. Для этого измените Source="file://c:/ms_logo.jpg" на Source="ms_logo.jpg".

Пути

Помимо Image ещё одним интересным элементом является Path. Путь — это объект, который может нарисовать ряд подключенных линий и кривых. Он ведет себя аналогично Image по отношению к его FlowDirection; например, его RightToLeftFlowDirection представляет собой горизонтальное зеркальное отражение своего LeftToRight. Однако в отличие от Image, Path наследует FlowDirection от контейнера, и не нужно явно его указывать.

В следующем примере нарисовывается простая стрелка с помощью 3 линий. Первая стрелка наследует направление потока от RightToLeft, так что её начальные и конечные точки измеряются от корня StackPanel справа. Вторая стрелка, которая имеет явное RightToLeftFlowDirection значение, также начинается с правой стороны. Однако третья стрелка имеет свой начальный корень на левой стороне. Дополнительные сведения о рисовании см. LineGeometry и GeometryGroup.

<StackPanel 
  xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' 
  FlowDirection="RightToLeft">

  <Path Stroke="Blue" StrokeThickness="4">
    <Path.Data>
      <GeometryGroup >
        <LineGeometry StartPoint="300,10" EndPoint="350,30" />
        <LineGeometry StartPoint="10,30" EndPoint="352,30" />
        <LineGeometry StartPoint="300,50" EndPoint="350,30" />
      </GeometryGroup>
    </Path.Data>
  </Path>

  <Path Stroke="Red" StrokeThickness="4" FlowDirection="RightToLeft">
    <Path.Data>
      <GeometryGroup >
        <LineGeometry StartPoint="300,10" EndPoint="350,30" />
        <LineGeometry StartPoint="10,30" EndPoint="352,30" />
        <LineGeometry StartPoint="300,50" EndPoint="350,30" />
      </GeometryGroup>
    </Path.Data>
  </Path>
 
  <Path Stroke="Green" StrokeThickness="4" FlowDirection="LeftToRight">
    <Path.Data>
      <GeometryGroup >
        <LineGeometry StartPoint="300,10" EndPoint="350,30" />
        <LineGeometry StartPoint="10,30" EndPoint="352,30" />
        <LineGeometry StartPoint="300,50" EndPoint="350,30" />
      </GeometryGroup>
    </Path.Data>
  </Path>
</StackPanel>

На следующем рисунке показаны выходные данные предыдущего примера со стрелками, нарисованными с помощью Path элемента:

Рисунок, иллюстрирующий стрелки, нарисованные с помощью элемента Path.

Image и Path — это два примера того, как WPF использует FlowDirection. Помимо размещения элементов пользовательского интерфейса в определенном направлении в контейнере, FlowDirection можно использовать с такими элементами, как InkPresenter, которые отображают чернила на поверхности, LinearGradientBrush, RadialGradientBrush. Всякий раз, когда требуется поведение справа налево для содержимого, которое имитирует поведение слева направо, или наоборот, Windows Presentation Foundation (WPF) предоставляет эту возможность.

Подстановка чисел

Исторически Windows поддерживала подстановку чисел, позволяя представлять цифры в разных культурных формах для одних и тех же цифр, сохраняя внутреннее хранилище этих цифр, объединенное для различных языков и регионов, например, числа хранятся в известных шестнадцатеричных значениях, 0x40, 0x41, но отображаются в соответствии с выбранным языком.

Это позволило приложениям обрабатывать числовые значения без необходимости их преобразования из одного языка в другой, например, пользователь может открыть электронную таблицу Microsoft Excel в локализованных арабских окнах и просмотреть цифры, сформированные на арабском языке, но открыть его в европейской версии Windows и увидеть общее представление одинаковых чисел. Это также необходимо для других символов, таких как разделители-запятые и процентные символы, так как они обычно сопровождают числа в том же документе.

Windows Presentation Foundation (WPF) продолжает ту же традицию, и добавляет дополнительную поддержку этой функции, которая позволяет более контролировать, когда и как используется подстановка. Хотя эта функция предназначена для любого языка, особенно полезно в двунаправленном содержимом, где формирование цифр для конкретного языка обычно является проблемой для разработчиков приложений из-за различных региональных параметров, на которых может работать приложение.

Основное свойство, управляющее работой подстановки чисел в Windows Presentation Foundation (WPF), является свойством зависимости Substitution. Класс NumberSubstitution указывает, как отображаются числа в тексте. Он имеет три общедоступных свойства, определяющих его поведение. Ниже приведена сводка по каждому из свойств:

CultureSource:

Это свойство определяет, как устанавливаются культурные нормы для чисел. Он принимает одно из трех NumberCultureSource значений перечисления.

  • Переопределение: культура чисел определяется свойством CultureOverride.

  • Текст: числовая культура — это культура текстового сегмента. В разметке это будет xml:lang или его свойство алиаса Language (Language или Language). Кроме того, это значение по умолчанию для классов, производных от FrameworkContentElement. К таким классам относятся System.Windows.Documents.Paragraph, System.Windows.Documents.TableSystem.Windows.Documents.TableCell и т. д.

  • Пользователь: числовая культура — это культура текущего потока. Это свойство используется по умолчанию для всех подклассов, таких FrameworkElement как Page, Window и TextBlock.

CultureOverride:

Свойство CultureOverride используется только если свойство CultureSource установлено на Override; в противном случае оно игнорируется. Он определяет числовой формат в культуре. Значение nullпо умолчанию интерпретируется как en-US.

Подстановка:

Это свойство указывает тип подстановки чисел для выполнения. Он принимает одно из следующих NumberSubstitutionMethod значений перечисления.

  • AsCulture: Метод подстановки определяется на основе свойства числовой культуры NumberFormatInfo.DigitSubstitution. Это значение по умолчанию.

  • Context: Если числовая культура является арабской или персидской, то это указывает, что цифры зависят от контекста.

  • European: числа всегда отображаются как европейские цифры.

  • NativeNational: Числа отображаются с использованием национальных цифр для числовой культуры, как указано культурой чиселNumberFormat.

  • Traditional: числа отрисовываются с помощью традиционных цифр для языка и региональных параметров. Для большинства языков и региональных параметров это то же самое, что NativeNationalи для большинства региональных параметров. NativeNational Хотя используется латинские цифры для некоторых арабских культур, хотя данное значение приводит к использованию арабских цифр для всех арабских культур.

Что такое значения означают для разработчика двунаправленного содержимого? В большинстве случаев разработчику может потребоваться только определить FlowDirection, а язык каждого текстового элемента пользовательского интерфейса, например Language="ar-SA", и NumberSubstitution логика заботится об отображении чисел в соответствии с правильным пользовательским интерфейсом. В следующем примере показано использование арабских и английских чисел в приложении Windows Presentation Foundation (WPF), работающем в арабской версии Windows.

<Page 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
  <StackPanel>
   <TextBlock Background="LightGreen" FontSize="32" 
      Language="ar-SA" FlowDirection="RightToLeft">1+2=3</TextBlock>
   <TextBox Background="LightGreen" FontSize="32" 
      Language="ar-SA" FlowDirection="RightToLeft">1+2=3</TextBox>
   <TextBlock Background="LightBlue" FontSize="32">1+2=3</TextBlock>
   <TextBox Background="LightBlue" FontSize="32">1+2=3</TextBox>
 </StackPanel>
</Page>

На следующем рисунке показаны выходные данные предыдущего примера, если вы работаете в арабской версии Windows с арабским и английским номерами:

Рисунок, показывающий арабские и английские цифры.

Это FlowDirection было важно в этом случае, так как установка FlowDirection на LeftToRight вместо этого дала бы европейские цифры. В следующих разделах описывается унифицированное отображение цифр в документе. Если этот пример не запущен на арабской версии Windows, все цифры отображаются как европейские цифры.

Определение правил подстановки

В реальном приложении может потребоваться программно задать язык. Например, необходимо задать xml:lang атрибут так же, как и тот, который используется пользовательским интерфейсом системы, или изменить язык в зависимости от состояния приложения.

Если вы хотите внести изменения в зависимости от состояния приложения, используйте другие функции, предоставляемые Windows Presentation Foundation (WPF).

Сначала задайте компонент NumberSubstitution.CultureSource="Text"приложения. Используя этот параметр, убедитесь, что параметры не приходят из пользовательского интерфейса для текстовых элементов, имеющих "User" в качестве значения по умолчанию, например TextBlock.

Рассмотрим пример.

<TextBlock
   Name="text1" NumberSubstitution.CultureSource="Text">
   1234+5679=6913
</TextBlock>

В соответствующем коде C# установите свойство Language, например, на значение "ar-SA".

text1.Language = System.Windows.Markup.XmlLanguage.GetLanguage("ar-SA");

Если необходимо задать Language для свойства язык пользовательского интерфейса текущего пользователя, используйте следующий код.

text1.Language = System.Windows.Markup.XmlLanguage.GetLanguage(System.Globalization.CultureInfo.CurrentUICulture.IetfLanguageTag);

CultureInfo.CurrentCulture представляет текущую культуру, используемую текущим потоком во время выполнения.

Окончательный пример XAML должен быть похож на следующий пример.

<Page x:Class="WindowsApplication.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Code Sample" Height="300" Width="300"
>
    <StackPanel>
      <TextBlock Language="ar-SA" 
         FlowDirection="RightToLeft">عربى: 1+2=3
      </TextBlock>
      <TextBlock Language="ar-SA" 
         FlowDirection="RightToLeft" 
         NumberSubstitution.Substitution="European">عربى: 1+2=3 
      </TextBlock>
    </StackPanel>
</Page>

Последний пример C# должен быть аналогичен следующему.

namespace BidiTest
{
    public partial class Window1 : Window
    {

        public Window1()
        {
            InitializeComponent();

            string currentLanguage =
                System.Globalization.CultureInfo.CurrentCulture.IetfLanguageTag;

            text1.Language = System.Windows.Markup.XmlLanguage.GetLanguage(currentLanguage);

            if (currentLanguage.ToLower().StartsWith("ar"))
            {
                text1.FlowDirection = FlowDirection.RightToLeft;
            }
            else
            {
                text1.FlowDirection = FlowDirection.LeftToRight;
            }
        }
    }
}

На следующем рисунке показано, как выглядит окно для любого языка программирования, отображающего арабские номера:

Рисунок, отображающий арабские цифры.

Использование свойства подстановки

Способ подстановки чисел в Windows Presentation Foundation (WPF) зависит как от языка текстового элемента, так и от его FlowDirection. Если направление чтения FlowDirection слева направо, то отображаются европейские цифры. Однако, если тексту предшествует арабский текст или язык установлен на "ar", то FlowDirection будет отображаться арабскими цифрами.

Однако в некоторых случаях может потребоваться создать единое приложение, например европейские цифры для всех пользователей. Или арабские цифры в Table ячейках с определенным Style. Один из простых способов сделать это с помощью Substitution свойства.

В следующем примере первый TextBlock не имеет Substitution набора свойств, поэтому алгоритм отображает арабские цифры, как ожидалось. Однако во втором TextBlock случае подстановка устанавливается на европейскую, что переопределяет стиль подстановки по умолчанию для арабских чисел, и отображаются цифры в европейском формате.

<Page x:Class="WindowsApplication.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Code Sample" Height="300" Width="300"
>
    <StackPanel>
      <TextBlock Language="ar-SA" 
         FlowDirection="RightToLeft">عربى: 1+2=3
      </TextBlock>
      <TextBlock Language="ar-SA" 
         FlowDirection="RightToLeft" 
         NumberSubstitution.Substitution="European">عربى: 1+2=3 
      </TextBlock>
    </StackPanel>
</Page>