简体   繁体   English

如何从XAML中CLR名称空间的类型而不是程序集(而不是声明类型)中映射类型?

[英]How do I map a type from a CLR namespace in XAML from an assembly other than the one where it's declared?

In XAML, I would like to use types from two different assemblies, each with their own namespace. 在XAML中,我想使用来自两个不同程序集的类型,每个程序集都有自己的命名空间。 Rather than declaring the namespaces explicitly in an xmlns:<xml-namespace>="<clr-namespace>" attribute, I would like to use the [XmlnsDefinition] assembly attribute to map a URI to the namespaces for those types. 与其在xmlns:<xml-namespace>="<clr-namespace>"属性中显式声明名称空间,不如使用[XmlnsDefinition]程序集属性将URI映射到这些类型的名称空间。

One of the assemblies is not relevant to WPF per se, so I would like to avoid it having any reference to WPF-related assemblies, and in particular the System.Xaml.dll assembly which would be required if that assembly used the [XmlnsDefinition] attribute. 其中一个程序集与WPF本身无关,因此我想避免它对WPF相关的程序集有任何引用,尤其是如果该程序集使用[XmlnsDefinition]需要System.Xaml.dll程序集。属性。

I have a Visual Studio Solution that is organized like this: 我有一个这样组织的Visual Studio解决方案:

Gu.Units.sln
    Gu.Units.csproj // no ref to System.Xaml here
    Gu.Units.Wpf.csproj // references Gu.Units and System.Xaml

In Gu.Units.Wpf.csproj I have this mapping: 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")]

I have tried to use it in XAML like this: 我试图像这样在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>

But for some reason, the namespace Gu.Units seems to be ignored. 但是由于某种原因,名称空间Gu.Units似乎被忽略了。 That is, it is not included in the XML namespace identified by the URI http://Gu.com/Units . 也就是说,它不包含在URI http://Gu.com/Units标识的XML名称空间中。 Instead, I get: 相反,我得到:

The name "LengthUnit" does not exist in the namespace " http://Gu.com/Units ". 名称“ LengthUnit”在名称空间“ http://Gu.com/Units ”中不存在。

An explicit namespace declaration in the XAML — ie having xmlns:units="clr-namespace:Gu.Units;assembly=Gu.Units" — works fine but I would also like to avoid that. XAML中的显式命名空间声明(即具有xmlns:units="clr-namespace:Gu.Units;assembly=Gu.Units" )可以正常工作,但我也想避免这种情况。

Is there a way that I can have my Gu.Units.Wpf.dll assembly provide the necessary [XmlnsDefinition] attribute to map the namespace from the Gu.Units.dll assembly, so that the latter does not itself need a reference to System.Xaml.dll , nor have any XAML-specific code in it at all? 有没有一种方法可以让我的Gu.Units.Wpf.dll程序集提供必要的[XmlnsDefinition]属性来映射Gu.Units.dll程序集的名称空间,以便后者本身不需要对System.Xaml.dll的引用System.Xaml.dll ,也根本没有任何特定于XAML的代码?

If I understand correctly, your question boils down to this: 如果我理解正确,那么您的问题可以归结为:

Having xmlns:units="clr-namespace:Gu.Units;assembly=Gu.Units" works fine but it is what I'm trying to avoid. 具有xmlns:units="clr-namespace:Gu.Units;assembly=Gu.Units"可以正常工作,但这是我要避免的事情。

Is there a way to do this? 有没有办法做到这一点?

The answer: no, there is not any way to avoid declaring some XML namespace prefix. 答案:不,没有任何方法可以避免声明一些 XML名称空间前缀。

  1. The [XmlnsPrefix] attribute has no effect on manually-authored XAML. [XmlnsPrefix]属性对手动创作的XAML无效。 Ie it does not introduce an xmlns prefix to the scope of the XAML. 也就是说,它引入了xmlns前缀XAML的范围。 It is simply a marker that XAML-authoring tools can retrieve so that if and when they autogenerate XAML declarations, they have a way to choose the xmlns prefix to use. 它只是XAML创作工具可以检索的标记,因此,当它们自动生成XAML声明时,它们就可以选择要使用的xmlns前缀。 Eg if you use the VS Designer to add a new object from a referenced library, it can look in that library to know that when adding the object to the XAML, it needs to add the appropriate xmlns: attribute to the outer container element, and use the specified prefix in the XAML where the object was added. 例如,如果您使用VS设计器从引用的库中添加新对象,则它可以在该库中查找以了解将对象添加到XAML时,它需要向外部容器元素中添加适当的xmlns:属性,并且在添加对象的XAML中使用指定的前缀。

  2. Neither of these attributes have any effect on XAML authored in the same assembly in which the attributes are specified. 这些属性都不会对在指定属性的同一程序集中创作的XAML产生任何影响。 The attributes are useful only in a fully-compiled assembly, and of course you don't get that until the XAML in the assembly has been compiled. 这些属性仅在完全编译的程序集中才有用,当然,只有在程序集中的XAML编译完成后,您才能使用这些属性。 So that XAML can't use the attributes. 这样XAML不能使用属性。

  3. That leaves the [XmlnsDefinition] attribute, when specified in an assembly that is referenced by the assembly containing the XAML currently being edited. 当在包含当前正在编辑的XAML的程序集引用的程序[XmlnsDefinition]指定程序集时, [XmlnsDefinition]属性。 In this scenario, the attribute is useful but still does not allow you to forego the xmlns: attribute declaration. 在这种情况下,该属性很有用,但仍然不允许您放弃xmlns:属性声明。 Instead what it does is allows you to map a URI (eg http://Gu.com/Units ) to one or more CLR namespaces. 相反,它的作用是允许您将URI(例如http://Gu.com/Units )映射到一个或多个CLR名称空间。 In this way, a single xmlns: prefix attribute declaration can a) refer to more than one CLR namespace, and b) do so without having the authored XAML have to actually name any CLR namespace specifically (ie it encapsulates the managed-code aspect of the assembly reference, hiding that behind a URI). 通过这种方式,单个xmlns:前缀属性声明可以a)引用多个CLR名称空间,并且b)这样做时,无需使创作的XAML实际专门命名任何CLR名称空间(即,它封装了CLR的托管代码方面)程序集引用,将其隐藏在URI后面)。

    In this way, instead of writing xmlns:units="clr-namespace:Gu.Units;assembly=Gu.Units" , you can write xmlns:units="http://Gu.com/Units" and that will allow the units xmlns prefix to qualify any type from any of the CLR namespaces that were attached to the http://Gu.com/Units URI via an [XmlnsDefinition] attribute. 这样,您可以编写xmlns:units="http://Gu.com/Units"而不是编写xmlns:units="clr-namespace:Gu.Units;assembly=Gu.Units" units xmlns前缀可以限定通过[XmlnsDefinition]属性附加到http://Gu.com/Units URI的任何CLR名称空间中的任何类型。

    But you still have to declare the XML namespace prefix. 但是您仍然必须声明XML名称空间前缀。 It's just that the declaration takes a different form than would otherwise be needed. 只是声明采用了与其他方式不同的形式。


Note: when multiple assemblies use the [XmlnsDefinition] attribute to declare CLR namespaces in the same URI as each other, all of the namespaces are referred to by that URI in XAML that references all of those assemblies. 注意:当多个程序集使用[XmlnsDefinition]属性在彼此相同的URI中声明CLR名称空间时,所有名称空间均由XAML中的URI引用,该URI引用所有这些程序集。 You can take advantage of this to join your own library's namespaces with those of a URI that you expect will already be referenced in the XAML (eg http://schemas.microsoft.com/winfx/2006/xaml/presentation ). 您可以利用此功能将您自己的库的命名空间与您希望在XAML中已经引用的URI的命名空间结合在一起(例如, http://schemas.microsoft.com/winfx/2006/xaml/presentation : http://schemas.microsoft.com/winfx/2006/xaml/presentation )。

As long as that URI is in fact used in an xmlns: attribute emitted in the XAML by the authoring tool, this "solves" the problem you are asking about. 只要创作工具在XAML中发出的xmlns:属性中实际上使用了该URI,就可以“解决”您正在询问的问题。 But conflating your own assembly namespaces with pre-existing ones from the framework is a hack and ill-advised. 但是,将您自己的程序集命名空间与框架中预先存在的程序集命名空间相结合是一个骇人且明智的选择。 Even if there are no type name conflicts, it's still a poor practice, and of course if there are type name conflicts, it can cause serious problems. 即使没有类型名称冲突,也仍然是一种不好的做法,当然,如果存在类型名称冲突,则可能导致严重的问题。


EDIT: 编辑:

Per your comment: 根据您的评论:

The problem I'm trying to solve is joining Gu.Units to the http://Gu.com/Units without adding a reference to System.Xaml for Gu.Units 我要解决的问题是将Gu.Units加入到http://Gu.com/Units,而没有为Gu.Units添加对System.Xaml的引用

From the documentation : 文档中

Apply one or more XmlnsDefinitionAttribute attributes to assemblies in order to identify the types within the assembly for XAML usage. 应用一个或多个XmlnsDefinitionAttribute属性组件,以便识别内的组件的类型XAML用法。 [emphasis mine] [强调我的]

Ie you can use [XmlnsDefinition] only to map types from a given namespace that are actually declared in the same assembly where the attribute itself is specified. 即,您只能使用[XmlnsDefinition]来映射给定名称空间中的类型,这些类型实际上是在指定属性本身的同一程序[XmlnsDefinition]声明的。

The attribute includes an AssemblyName property, which seems to indicate you could include types from other assemblies. 该属性包括AssemblyName属性,该属性似乎表明您可以包括来自其他程序集的类型。 This is the natural reading of the documentation, and was probably the intent of the usage of the attribute. 这是文档的自然阅读,并且可能是该属性的使用意图。 Unfortunately, the framework has no control over how other code consumes that attribute, and the XAML tools do in fact ignore it. 不幸的是,该框架无法控制其他代码如何使用该属性,而XAML工具实际上忽略了该属性。

The [XmlnsDefinition] attribute can be used only to map URIs to namespaces declared in the assembly in which the attribute is found. [XmlnsDefinition]属性只能用于将URI映射到在其中找到该属性的程序集中声明的名称空间。 You can specify other assembly names, but the XAML designer and compiler in Visual Studio pay no attention to the AssemblyName property. 您可以指定其他程序集名称,但是Visual Studio中的XAML设计器和编译器不注意AssemblyName属性。

The WPF team has acknowledged this to be a bug , but has stated that they will not fix the problem. WPF团队已经承认这是一个错误 ,但表示他们不会解决此问题。


It is possible to work around the issue on a type-by-type basis. 可以逐个解决该问题。 The most obvious approach is to declare a new type in the assembly where the [XmlnsDefinition] is specified, inheriting the type you want from the other assembly. 最明显的方法是在指定了[XmlnsDefinition]的程序[XmlnsDefinition]声明一个新类型,从而从另一个程序[XmlnsDefinition]继承所需的类型。 For example, in your Gu.Units.Wpf assembly, you could declare a type like this: 例如,在您的Gu.Units.Wpf程序Gu.Units.Wpf ,您可以声明如下类型:

public class LengthUnits : Gu.Units.LengthUnits { }

Then you would wind up using the type Gu.Units.Wpf.LengthUnits instead of Gu.Units.LengthUnits . 然后,您将使用类型Gu.Units.Wpf.LengthUnits而不是Gu.Units.LengthUnits Obviously, this will work only if the type is an unsealed reference type. 显然,这仅在类型是未密封的引用类型时才有效。 Also, depending on how the type is actually being used, you could wind up with problems where the code is trying to use an instance of Gu.Units.LengthUnits where an instance of Gu.Units.Wpf.LengthUnits is required. 另外,根据类型的实际使用方式,您可能会遇到一些问题,例如代码尝试使用Gu.Units.LengthUnits实例, Gu.Units.LengthUnits其中需要Gu.Units.Wpf.LengthUnits实例。 For simple one-way binding scenarios, this probably wouldn't come up but I can easily imagine other scenarios where it would. 对于简单的单向绑定方案,可能不会出现这种情况,但是我可以很容易地想象其他方案。

A less obvious way to work around the problem is to use the [TypeForwardedTo] attribute. 解决该问题的一种不太明显的方法是使用[TypeForwardedTo]属性。 For example, in your Gu.Units.Wpf assembly, you could include this: 例如,在您的Gu.Units.Wpf程序Gu.Units.Wpf ,您可以包括以下内容:

[assembly: TypeForwardedTo(typeof(Gu.Units.LengthUnits))]

This has the advantage that the type in question will be the same type. 这样做的好处是,所讨论的类型将是相同类型。 However, this is a runtime effect and does not play very well with the XAML designer tools. 但是,这是运行时的效果,在XAML设计器工具中不能很好地发挥作用。 Your project will build and run correctly, but the designer will still complain that "the type 'units:LengthUnits' was not found" . 您的项目将正确构建并运行,但是设计人员仍会抱怨“未找到类型'units:LengthUnits'”

I am not aware of any work-around that will address the issue more broadly, on a namespace basis. 我不知道有任何解决方法可以在命名空间的基础上更广泛地解决此问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 我如何从除主要的 class 访问 XAML object? - how do I access a XAML object from a class other than main? 当使用多个表时,如何从XAML ListView获取ID? - How do I get the id from a XAML ListView when more than one table is used? 为什么会出现异常:无法从程序集“ System.Xaml”加载类型“ xy”? - Why do I get the exception: Could not load type 'xy' from assembly 'System.Xaml'? 如何在任何基于CLR的语言程序集中找到给定类型的所有类型依赖? - How do I find all the type dependecies of a given type in any CLR based language assembly? CLR 如何从程序集中加载文件? - How does CLR load a file from an assembly? 如何从一个Xaml文件导航到另一个文件? - How do i navigate from one Xaml file to another? 从其他Assembly实例化ResourceDictionary xaml - Instantiate ResourceDictionary xaml from other Assembly 类型库“System_Windows_Forms”是从 CLR 程序集导出的,无法作为 CLR 程序集重新导入 - Type library 'System_Windows_Forms' was exported from a CLR assembly and cannot be re-imported as a CLR assembly 从C#/。NET程序集中,如何加载C ++ / CLR DLL并加载非托管DLL? - From a C#/.NET assembly, how do I load a C++/CLR DLL which loads an unmanaged DLL? Xamarin XAML:未从外部程序集中找到类型 - Xamarin XAML: Type is not found from external assembly
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM