[英]How do I map a type from a CLR namespace in XAML from an assembly other than the one where it's declared?
在XAML中,我想使用來自兩個不同程序集的類型,每個程序集都有自己的命名空間。 與其在xmlns:<xml-namespace>="<clr-namespace>"
屬性中顯式聲明名稱空間,不如使用[XmlnsDefinition]
程序集屬性將URI映射到這些類型的名稱空間。
其中一個程序集與WPF本身無關,因此我想避免它對WPF相關的程序集有任何引用,尤其是如果該程序集使用[XmlnsDefinition]
需要System.Xaml.dll
程序集。屬性。
我有一個這樣組織的Visual Studio解決方案:
Gu.Units.sln Gu.Units.csproj // no ref to System.Xaml here Gu.Units.Wpf.csproj // references Gu.Units and System.Xaml
在Gu.Units.Wpf.csproj
我有以下映射:
[assembly: XmlnsDefinition("http://Gu.com/Units", clrNamespace: "Gu.Units", AssemblyName = "Gu.Units")]
[assembly: XmlnsDefinition("http://Gu.com/Units", clrNamespace: "Gu.Units.Wpf", AssemblyName = "Gu.Units.Wpf")]
[assembly: XmlnsPrefix("http://Gu.com/Units", "units")]
我試圖像這樣在XAML中使用它:
<UserControl x:Class="Gu.Units.Wpf.Demo.Sample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:units="http://Gu.com/Units">
<Label Content="{x:Static units:LengthUnit.Millimetres}" />
</UserControl>
但是由於某種原因,名稱空間Gu.Units
似乎被忽略了。 也就是說,它不包含在URI http://Gu.com/Units
標識的XML名稱空間中。 相反,我得到:
名稱“ LengthUnit”在名稱空間“ http://Gu.com/Units ”中不存在。
XAML中的顯式命名空間聲明(即具有xmlns:units="clr-namespace:Gu.Units;assembly=Gu.Units"
)可以正常工作,但我也想避免這種情況。
有沒有一種方法可以讓我的Gu.Units.Wpf.dll
程序集提供必要的[XmlnsDefinition]
屬性來映射Gu.Units.dll
程序集的名稱空間,以便后者本身不需要對System.Xaml.dll
的引用System.Xaml.dll
,也根本沒有任何特定於XAML的代碼?
如果我理解正確,那么您的問題可以歸結為:
具有
xmlns:units="clr-namespace:Gu.Units;assembly=Gu.Units"
可以正常工作,但這是我要避免的事情。有沒有辦法做到這一點?
答案:不,沒有任何方法可以避免聲明一些 XML名稱空間前綴。
[XmlnsPrefix]
屬性對手動創作的XAML無效。 也就是說,它不引入了xmlns前綴XAML的范圍。 它只是XAML創作工具可以檢索的標記,因此,當它們自動生成XAML聲明時,它們就可以選擇要使用的xmlns前綴。 例如,如果您使用VS設計器從引用的庫中添加新對象,則它可以在該庫中查找以了解將對象添加到XAML時,它需要向外部容器元素中添加適當的xmlns:
屬性,並且在添加對象的XAML中使用指定的前綴。 [XmlnsDefinition]
指定程序集時, [XmlnsDefinition]
屬性。 在這種情況下,該屬性很有用,但仍然不允許您放棄xmlns:
屬性聲明。 相反,它的作用是允許您將URI(例如http://Gu.com/Units
)映射到一個或多個CLR名稱空間。 通過這種方式,單個xmlns:
前綴屬性聲明可以a)引用多個CLR名稱空間,並且b)這樣做時,無需使創作的XAML實際專門命名任何CLR名稱空間(即,它封裝了CLR的托管代碼方面)程序集引用,將其隱藏在URI后面)。 xmlns:units="http://Gu.com/Units"
而不是編寫xmlns:units="clr-namespace:Gu.Units;assembly=Gu.Units"
units
xmlns前綴可以限定通過[XmlnsDefinition]
屬性附加到http://Gu.com/Units
URI的任何CLR名稱空間中的任何類型。
注意:當多個程序集使用[XmlnsDefinition]
屬性在彼此相同的URI中聲明CLR名稱空間時,所有名稱空間均由XAML中的URI引用,該URI引用所有這些程序集。 您可以利用此功能將您自己的庫的命名空間與您希望在XAML中已經引用的URI的命名空間結合在一起(例如, http://schemas.microsoft.com/winfx/2006/xaml/presentation
: http://schemas.microsoft.com/winfx/2006/xaml/presentation
)。
只要創作工具在XAML中發出的xmlns:
屬性中實際上使用了該URI,就可以“解決”您正在詢問的問題。 但是,將您自己的程序集命名空間與框架中預先存在的程序集命名空間相結合是一個駭人且明智的選擇。 即使沒有類型名稱沖突,也仍然是一種不好的做法,當然,如果存在類型名稱沖突,則可能導致嚴重的問題。
編輯:
根據您的評論:
我要解決的問題是將Gu.Units加入到http://Gu.com/Units,而沒有為Gu.Units添加對System.Xaml的引用
從文檔中 :
應用一個或多個XmlnsDefinitionAttribute屬性組件,以便識別內的組件的類型XAML用法。 [強調我的]
即,您只能使用[XmlnsDefinition]
來映射給定名稱空間中的類型,這些類型實際上是在指定屬性本身的同一程序[XmlnsDefinition]
聲明的。
該屬性包括AssemblyName
屬性,該屬性似乎表明您可以包括來自其他程序集的類型。 這是文檔的自然閱讀,並且可能是該屬性的使用意圖。 不幸的是,該框架無法控制其他代碼如何使用該屬性,而XAML工具實際上忽略了該屬性。
[XmlnsDefinition]
屬性只能用於將URI映射到在其中找到該屬性的程序集中聲明的名稱空間。 您可以指定其他程序集名稱,但是Visual Studio中的XAML設計器和編譯器不注意AssemblyName
屬性。
WPF團隊已經承認這是一個錯誤 ,但表示他們不會解決此問題。
可以逐個解決該問題。 最明顯的方法是在指定了[XmlnsDefinition]
的程序[XmlnsDefinition]
聲明一個新類型,從而從另一個程序[XmlnsDefinition]
繼承所需的類型。 例如,在您的Gu.Units.Wpf
程序Gu.Units.Wpf
,您可以聲明如下類型:
public class LengthUnits : Gu.Units.LengthUnits { }
然后,您將使用類型Gu.Units.Wpf.LengthUnits
而不是Gu.Units.LengthUnits
。 顯然,這僅在類型是未密封的引用類型時才有效。 另外,根據類型的實際使用方式,您可能會遇到一些問題,例如代碼嘗試使用Gu.Units.LengthUnits
實例, Gu.Units.LengthUnits
其中需要Gu.Units.Wpf.LengthUnits
實例。 對於簡單的單向綁定方案,可能不會出現這種情況,但是我可以很容易地想象其他方案。
解決該問題的一種不太明顯的方法是使用[TypeForwardedTo]
屬性。 例如,在您的Gu.Units.Wpf
程序Gu.Units.Wpf
,您可以包括以下內容:
[assembly: TypeForwardedTo(typeof(Gu.Units.LengthUnits))]
這樣做的好處是,所討論的類型將是相同類型。 但是,這是運行時的效果,在XAML設計器工具中不能很好地發揮作用。 您的項目將正確構建並運行,但是設計人員仍會抱怨“未找到類型'units:LengthUnits'” 。
我不知道有任何解決方法可以在命名空間的基礎上更廣泛地解決此問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.