TypeConverter 和 XAML
本主題介紹將字串的類型轉換當成一般 XAML 語言功能的目的。 在 .NET Framework 中,TypeConverter 類別具有特殊用途,可作為受控自訂義類別實作的一部分,該類別可作為 XAML 屬性使用方式的屬性值。 如果您撰寫自訂義類別,並希望該類別的實例可用作 XAML 中可設定的屬性值,您可能需要將 TypeConverterAttribute 應用於您的類別、撰寫自訂義 TypeConverter 類別,或兩者都需要進行。
類型轉換概念
XAML 和字串值
在 XAML 檔案中設定屬性值時,該值的初始類型是純文字的字串。 即使是其他基本類型,例如 Double,最初對於 XAML 處理器來說也是文字字串。
XAML 處理器需要兩項資訊才能處理屬性值。 第一項資訊是正在設定之屬性的實值類型。 任何定義屬性值並在 XAML 中處理的字串最後必須轉換或解析成該類型的值。 如果值是 XAML 剖析器可理解的基本類型 (例如數值),則會嘗試直接轉換字串。 如果值是一個列舉,則用來檢查名稱的字串會符合該列舉中的具名常數。 如果值不是剖析器所辨識的基本類型,也不是列舉,則上述類型必須能夠根據已轉換的字串提供類型的執行個體或值。 您可以藉由指定類型轉換器類別來完成此動作。 類型轉換子實際上是一個 Helper 類別,可用於提供另一個類別的值,這兩者均適用於 XAML 案例,可能也適用於利用 .NET 程式碼進行程式碼呼叫。
在 XAML 中使用現有的類型轉換行為
根據您對基礎 XAML 概念的熟悉程度而定,您可能已經在基本應用程式 XAML 中使用類型轉換行為而不自知。 例如,WPF 定義了數百個屬性,它們的值類型是 Point。 Point 是一個值,描述平面座標空間中座標,它實際上只有兩個重要的屬性:X 和 Y。當您在 XAML 中指定一個點時,會將它指定為一個帶有分隔符號(通常是逗號)的字串,介於您提供的 X 和 Y 值之間。 例如: <LinearGradientBrush StartPoint="0,0" EndPoint="1,1"/>
。
即使是這種簡單的 Point 類型,在 XAML 中的簡單用法也牽涉到類型轉換器。 在這種情況下,這就是 PointConverter 類別。
類別層級所定義之 Point 類型轉換器可簡化採用 Point之所有屬性的標記使用方式。 若未在此處使用類型轉換器,您就需要針對先前所示的同一個範例使用下列更多較為詳細的標記:
<LinearGradientBrush>
<LinearGradientBrush.StartPoint>
<Point X="0" Y="0"/>
</LinearGradientBrush.StartPoint>
<LinearGradientBrush.EndPoint>
<Point X="1" Y="1"/>
</LinearGradientBrush.EndPoint>
</LinearGradientBrush>
是否要使用類型轉換字串或較為詳細的對等語法,通常是編碼樣式的選擇。 您的 XAML 工具工作流程可能也會影響值的設定方式。 一些 XAML 工具傾向於發出最詳細格式的標記,因為較容易反覆存取設計工具檢視或它自己的序列化機制。
透過檢查類別(或屬性)是否套用 TypeConverterAttribute ,通常可以在 WPF 和 .NET Framework 類型上發現現有的類型轉換器。 這個屬性將基於 XAML 用途以及其他可能的用途,針對該類型的值,為支援類型轉換器的類別命名。
類型轉換器和標記延伸
標記延伸和類型轉換器會根據 XAML 處理器行為和套用它們的案例來填滿正交角色。 儘管有適合標記延伸使用的內容,但標記延伸負責提供值的屬性類型轉換行為在標記延伸實作中通常不會遭到檢查。 換句話說,即使標記延伸傳回文字字串做為其 ProvideValue
輸出,也不會在該字串上叫用套用至特定屬性或屬性值類型的類型轉換行為。一般來說,標記延伸的目的是在未涉及任何類型轉換器的情況下,處理字串並傳回物件。
需要標記延伸而不是類型轉換器的一個常見情況是參考現有的物件。 無狀態類型轉換器充其量只能產生新的執行個體,但這可能不是令人滿意的情況。 如需標記延伸的詳細資訊,請參閱標記延伸和 WPF XAML。
原生類型轉換器
在 XAML 剖析器中的 WPF 和 .NET Framework 實作中,有些特定類型具有原生類型轉換處理,但卻不是依慣例會被視為基本類型的類型。 這類類型的範例是 DateTime。 這種做法基於 .NET Framework 架構的運作方式:類型 DateTime 於 .NET 中最基本的程式庫 mscorlib 中定義。 由於 DateTime 不能被來自其他組件的屬性標註(該組件引入相依性,而 TypeConverterAttribute 來自 System),因此無法支援通常的類型轉換器發現機制。 而是 XAML 剖析器會有一份需要這類原生處理的類型清單,這些類型的處理方式會與真正基本類型的處理方式類似 (在 DateTime 的情況下,這涉及到呼叫 Parse。)
實作類型轉換器
TypeConverter
在先前提到的 Point 範例中,提到了 PointConverter 類別。 在 .NET 的 XAML 實作中,所有用於 XAML 目的的類型轉換器都衍生自基底類別 TypeConverter。 TypeConverter 類別早在 XAML 存在之前的 .NET Framework 版本中就已經存在,其最初用途之一是為視覺化設計工具中的屬性對話方塊提供字串轉換。 在 XAML 中,TypeConverter 的角色可擴展成字串來回轉換的基底類別,從而可以解析字串屬性值,並可將特定物件屬性在執行階段的值處理回字串,以便將其序列化為屬性。
TypeConverter 定義了四個與 XAML 處理目的相關的成員,用於字串的來回轉換。
其中最重要的方法是 ConvertFrom。 這個方法會將輸入字串轉換為所需的物件類型。 嚴格來說,ConvertFrom 方法可以將更多類型轉換為轉換器的目標類型,從而達到 XAML 以外的目的,例如支援在執行階段轉換的功能,但對於 XAML 來說,只有能夠處理 String 輸入的程式碼路徑才是關鍵。
其次重要的方法是 ConvertTo。 如果將應用程式轉換為標記表示法 (例如,如果將其儲存為 XAML 檔案),則ConvertTo 負責產成標記表示法。 在此情況下,XAML 關鍵程式碼路徑是當您傳遞 String 的 destinationType
時。
CanConvertTo 和 CanConvertFrom 是服務查詢 TypeConverter 實作之功能時所使用的支援方法。 您必須實作這些方法來傳回轉換器對等轉換方法所支援類型特有案例的 true
。 基於 XAML,這通常表示 String 類型。
XAML 的文化特性資訊和類型轉換器
每個 TypeConverter 實作對於何謂有效轉換字串都能自訂解釋,並且可以使用或忽略作為參數傳遞的類型描述。 有一個關於文化特性和 XAML 類型轉換的重要考量。 XAML 完全支援使用可當地語系化的字串做為屬性值。 但不支援使用那個可當地語系化的字串做為具有特定文化特性需求的類型轉換器輸入,因為 XAML 屬性值的類型轉換器會使用 en-US
文化特性,來包含必然的固定語言剖析行為。 如需了解此限制的設計原因,可參閱 XAML 語言規格 ([MS-XAML])。
在文化特性可能是問題的範例中,某些文化特性會使用逗號做為數字的小數點分隔符號。 這將與許多 WPF XAML 類型轉換器所具備的行為相衝突,該行為是使用逗號做為分隔符號 (根據歷程的前置參照,例如,常見的 X,Y 格式或逗號分隔清單)。 即使是在局部的 XAML 中傳遞文化特性 (將 Language
或 xml:lang
設為 sl-SI
文化特性,以這種方式使用逗號代表小數點的文化特性範例),還是無法解決問題。
實作 ConvertFrom
若要可做為支援 XAML 的 TypeConverter 實作來重複使用,該轉換器的 ConvertFrom 方法必須接受字串做為 value
參數。 如果字串的格式有效,並且可以由 TypeConverter 實作轉換,則傳回的物件必須能轉換成該屬性所期類型。 否則, ConvertFrom 實作必須傳回 null
。
每個 TypeConverter 實作對於何謂有效轉換字串都能自訂解釋,並且可以使用或忽略作為參數傳遞的類型描述或文化情境。 不過,WPF XAML 處理可能不會在所有情況下都將值傳遞至類型描述內容,也可能不會根據 xml:lang
來傳遞文化特性。
注意
請勿使用大括號字元 (特別是 {)做為字串格式的可能元素。 這些字元保留做為標記延伸序列的進入及結束。
實作 ConvertTo
ConvertTo 可能用於序列化支援。 透過自訂類型和其類型轉換器之 ConvertTo 的序列化支援不是絕對需求。 不過,如果您正在實作控制項,或使用功能某部分的序列化或類別設計,則應該實作 ConvertTo。
若要作為支援 XAML 的 TypeConverter 實作使用,該轉換器的 ConvertTo 方法必須接受所支援類型 (或值) 的執行個體做為 value
參數之用。 destinationType
參數的類型是 String時,傳回的物件必須可以轉換為 String。 傳回的字串必須代表 value
的序列化值。 理想情況下,您選擇的序列化格式應能夠產生相同的值,即使該字串被傳遞給相同轉換器的 ConvertFrom 實作,也不會有明顯的資訊損失。
如果無法序列化該值,或者轉換器不支援序列化,ConvertTo 實作必須返回 null
,並允許擲回例外狀況。 不過,如果您確實擲回例外狀況,則應該報告無法使用該轉換做為 CanConvertTo 實作的一部分;因此,最好能先使用 CanConvertTo 檢查以避免例外狀況。
如果 destinationType
參數不是類型 String,您可以選擇自己的轉換器處理方式。 一般而言,您會回復成基底實作處理,而在基底 ConvertTo 中會引發特定例外狀況。
實作 CanConvertTo
您的 CanConvertTo 實作應該傳回類型 true
之 destinationType
的 String,否則會進行基底實作。
實作 CanConvertFrom
您的 CanConvertTo 實作應該傳回類型 true
之 destinationType
的 String,否則會進行基底實作。
套用 TypeConverterAttribute
為了讓您的自定義類型轉換器成為 XAML 處理器自訂類別的代理類型轉換器,您必須將 TypeConverterAttribute 套用至您的類別定義。 您透過屬性指定的 ConverterTypeName 必須是您自訂類型轉換器的類型名稱。 如果已套用這個屬性,當 XAML 處理器處理屬性類型使用您自訂類別類型的值時,就可以輸入字串並傳回物件執行個體。
您也可以提供每個屬性的類型轉換器。 將 TypeConverterAttribute 套用至屬性定義 (主要定義,非其內的 get
/set
實作),而不是將它套用至類別定義。 屬性的類型必須符合您自訂類型轉換器所處理的類型。 如果已套用這個屬性,則在 XAML 處理器處理該屬性的值時,可以處理輸入字串,並傳回物件執行個體。 如果您選擇使用的屬性類型來自 Microsoft .NET Framework 或來自無法控制類別定義且無法在該處套用 TypeConverterAttribute 的某個其他程式庫,則每一屬性類型轉換器技術特別有用。