共用方式為


WPF 中的雙向功能概觀

與任何其他開發平台不同,WPF 的許多功能都支援雙向內容的快速開發,例如,在相同的文件中,混合使用由左至右和由右至左資料。 同時,WPF 會為需要雙向功能的使用者 (例如說阿拉伯文和希伯來文的使用者) 建立絕佳體驗。

下列各節說明許多雙向功能以及說明如何達到最佳雙向內容顯示的範例。 大部分的範例會使用 XAML,但是您可以輕鬆地將這些概念套用至 C# 或 Microsoft Visual Basic 程式碼。

FlowDirection

定義 WPF 應用程式中內容流程方向的基本屬性為 FlowDirection。 此屬性可以設定為以下其中一個列舉值,LeftToRightRightToLeft。 屬性可供繼承自 FrameworkElement 的所有 WPF 元素使用。

下列範例會設定 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>

下圖顯示如何轉譯先前的程式碼。

說明不同流程方向的圖形。

使用者介面 (UI) 樹狀結構內的元素會從其容器繼承 FlowDirection。 在下列範例中,TextBlock 位於 WindowGrid 內。 為 Window 設定 FlowDirection 意指也會為 GridTextBlock 設定。

下列範例會示範如何設定 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

下圖顯示上述範例的輸出:

說明明確流程方向變更的圖形。

FlowDocument

許多開發平台 (例如 HTML、Win32 和 Java) 提供進行雙向內容開發的特殊支援。 標記語言 (例如 HTML) 提供必要標記,讓內容作者以任何必要的方向來顯示文字;例如,HTML 4.0 標記 "dir" 會採用 "rtl" 或 "ltr" 作為值。 此標籤類似於 FlowDirection 屬性,但 FlowDirection 屬性的運作方式更進階,可配置文字內容,而且可用於文字以外的內容。

在可提供文字、資料表、影像和其他元素之組合的 UI 項目中。 下列各節中的範例會使用這個項目。

可以多種方式將文字新增至 FlowDocument。 這樣做的簡單方式是透過 Paragraph,而它是用來分組文字這類內容的區塊層級元素。 若要將文字新增至內嵌層級元素,範例會使用 SpanRunSpan 是用於分組其他內嵌元素的內嵌層級流動內容元素,而 Run 是要包含未格式化文字執行的內嵌層級流動內容元素。 Span 可以包含多個 Run 元素。

第一個文件範例包含具有許多網路共用名稱的文件;例如 \\server1\folder\file.ext。 不論此網路連結出現在阿拉伯文文件還是英文文件中,您一定都會想要以相同的方式來顯示它。 下圖說明如何使用 Span 元素,並在阿拉伯文 RightToLeft 文件中顯示連結:

說明使用 Span 元素的圖形。

因為文字是 RightToLeft,所以所有 "\" 這類特殊字元都會以由右至左的順序區隔文字。 這會導致未以正確順序顯示連結,因此,若要解決此問題,則必須內嵌文字,才能保留個別 Run 流向 LeftToRight。 解決問題的較佳方式是將較不常用的英文文字內嵌到較大的阿拉伯文 Run,而不需要每種語言都有不同的 Span

下圖說明使用內嵌在 Span 元素之 Run 元素的圖形:

說明內嵌在 Span 元素之 Run 元素的圖形。

下列範例會示範如何在文件中使用 RunSpan 元素。

<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 元素也會被視為具有不同的雙向範圍,這表示 Span 元素是在容器的 FlowDirection 中排序,只有 Span 元素內的內容會遵循 SpanFlowDirection

下圖顯示數個 TextBlock 元素的流程方向。

說明文字方向不同之文字區塊的圖形。

下列範例會示範如何使用 SpanRun 元素來產生上圖中所顯示的結果。

<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,而針對 XAML,這是 en-US。 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:langFlowDirection 值。

具有非文字項目的 FlowDirection

FlowDirection 不僅定義文字元素中的文字流向,也會定義幾乎每個其他 UI 項目的流向。 下圖顯示使用橫向 LinearGradientBrush 繪製其具有由左至右漸層之背景的 ToolBar

顯示具有由左至右漸層之工具列的圖形。

FlowDirection 設定為 RightToLeft 之後,不僅會由右至左排列 ToolBar 按鈕,甚至會將 LinearGradientBrush 的位移重新調整為由右至左。

下圖顯示 LinearGradientBrush 的重新調整。

顯示具有由右至左漸層之工具列的圖形。

下列範例會繪製 RightToLeftToolBar。 (若要由左至右繪製,請移除 ToolBar 上的 FlowDirection 屬性。

<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 中,它可與定義 Image 統一資源識別項 (URI) 的 Source 屬性搭配使用。

不同於其他 UI 項目,Image 不會從容器繼承 FlowDirection。 不過,如果明確將 FlowDirection 設定為 RightToLeft,則 Image 會橫向翻轉顯示。 這會實作為方便使用的功能,讓開發人員用於雙向內容;因為在某些情況下,水平翻轉影像會產生所要的效果。

下圖顯示已翻轉的 Image

說明已翻轉影像的圖形。

下列範例會說明 Image 無法從 StackPanel 繼承 FlowDirection

注意

您的 C:\ 磁碟機上必須要有名為 ms_logo.jpg 的檔案,才能執行此範例。

<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。 路徑是物件,可繪製一系列連接的線條和曲線。 其行為方式與其 FlowDirection 相關的 Image 類似; 例如,其 RightToLeftFlowDirection 是其 LeftToRight 的橫向鏡像。 不過,不同於 ImagePath 會從容器繼承其 FlowDirection,而且不需要明確指定它。

下列範例會繪製一個使用 3 條線的簡單箭號。 第一個箭號會從 StackPanel 繼承 RightToLeft 流程方向,以便從右側的根測量其起點和終點。 具有明確 RightToLeftFlowDirection 的第二個箭號也會從右側開始。 不過,第三個箭號的起始根在左邊。 如需繪圖的詳細資訊,請參閱 LineGeometryGeometryGroup

<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 元素所繪製箭號的圖形。

ImagePath 是 WPF 如何使用 FlowDirection 的兩個範例。 除了在容器內以特定方向配置 UI 項目之外,FlowDirection 可以搭配 InkPresenter 等元素使用,以呈現表面的筆跡,即 LinearGradientBrushRadialGradientBrush。 只要模擬由左至右行為的內容需要由右至左的行為,Windows Presentation Foundation (WPF) 就會提供該功能,反之亦然。

數字替代

過去,Windows 已支援數字替代,方法是允許為相同數字呈現不同文化特性形狀,同時在不同的地區設定之間統一這些數字的內部儲存體;例如,數字會儲存在其已知十六進位值 0x40、0x41,但根據選取的語言予以顯示。

這已允許應用程式在不需要將數值轉換為另一種語言的情況下來處理數值;例如,使用者可以在當地語系化的阿拉伯文 Windows 中開啟 Microsoft Excel 試算表,並看到阿拉伯數字,但在歐洲版 Windows 中開啟它,則會看到以歐洲語言呈現相同的數字。 針對逗號分隔符號和百分比符號這類其他符號,這也是必要的,因為在相同的文件中,它們通常會伴隨數字。

Windows Presentation Foundation (WPF) 會持續使用相同的傳統,並新增此替代的進一步支援,讓使用者更深入控制該何時和如何使用這項功能。 雖然這項功能設計用於任何語言,但特別適用於雙向內容,其中特定語言的成形數字通常會是應用程式開發人員的挑戰,因為應用程式可能會在各種文化特性中執行。

控制 Windows Presentation Foundation (WPF) 中數字替代運作方式的核心屬性是 Substitution 相依性屬性。 NumberSubstitution 類別會指定文字中的數字顯示方式。 它有三個定義其行為的公用屬性。 下列是每個屬性的摘要:

CultureSource

這個屬性指定如何判斷數字的文化特性。 採用三個 NumberCultureSource 列舉值的其中一個。

CultureOverride

只有當 CultureSource 屬性設定為 Override 時,才會使用 CultureOverride 屬性,否則將忽略。 它指定數字文化特性。 null 值 (預設值) 會解譯為 en-US。

替代

這個屬性指定要執行的數字替代類型。 採用下列其中一個 NumberSubstitutionMethod 列舉值:

  • AsCulture:取代方法係由數字文化特性的 NumberFormatInfo.DigitSubstitution 屬性決定。 這是預設值。

  • Context:如果數字文化特性為阿拉伯或波斯文化特性,它會依據內容指定數字。

  • European:數字一律會轉譯為歐洲數字。

  • NativeNational:使用國際數字的數字文化特性來呈現數字,如同文化特性的 NumberFormat 所指定。

  • Traditional:使用傳統數字的數字文化特性來呈現數字。 對大多數的文化特性來說,這會與 NativeNational 相同。 不過,NativeNational 卻會在某些阿拉伯文化特性中呈現拉丁數字,而此值則會在所有的阿拉伯文化特性中呈現阿拉伯數字。

這些值對雙向內容開發人員的意義為何? 在大部分情況下,開發人員可能只需要定義每個文字 UI 項目的 FlowDirection 和語言,例如 Language="ar-SA"NumberSubstitution 邏輯會負責根據正確的 UI 來顯示數字。 下列範例示範如何在阿拉伯文版 Windows 中所執行的 Windows Presentation Foundation (WPF) 應用程式中使用阿拉伯和英文數字。

<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 屬性設定為系統 UI 所使用的相同屬性,或可能會根據應用程式狀態來變更語言。

如果您想要根據應用程式的狀態來進行變更,請使用 Windows Presentation Foundation (WPF) 所提供的其他功能。

首先,設定應用程式元件的 NumberSubstitution.CultureSource="Text"。 使用此設定可確保設定不會來自預設值為 "User" 之文字元素的 UI,例如 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 屬性設定為目前使用者的 UI 語言,請使用下列程式碼。

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",且 FlowDirectionRightToLeft,則會改為轉譯阿拉伯數字。

不過,在某些情況下,您可能想建立統一的應用程式,例如所有使用者都使用歐洲數字。 或具有特定 StyleTable 儲存格中的阿拉伯數字。 使用 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>