[英]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.