如何在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?

查看:85
本文介绍了如何在XAML中的CLR命名空间中从声明的程序集以外的程序集映射类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在XAML中,我想使用来自两个不同程序集的类型,每个程序集都有自己的命名空间.我不想使用[XmlnsDefinition]程序集属性将URI映射到这些类型的名称空间,而不是在xmlns:<xml-namespace>="<clr-namespace>"属性中明确声明名称空间.

In XAML, I would like to use types from two different assemblies, each with their own namespace. 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.

其中一个程序集与WPF本身无关,因此我想避免它涉及与WPF相关的程序集,特别是如果System.Xaml.dll程序集使用属性.

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.

我有一个这样组织的Visual Studio解决方案:

I have a Visual Studio Solution that is organized like this:


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中,我具有以下映射:

In Gu.Units.Wpf.csproj I have this mapping:

[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中使用它:

I have tried to use it in XAML like this:

<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名称空间中.相反,我得到了:

But for some reason, the namespace Gu.Units seems to be ignored. That is, it is not included in the XML namespace identified by the URI http://Gu.com/Units. Instead, I get:

名称空间" http://Gu.com/Units "中不存在名称"LengthUnit"

The name "LengthUnit" does not exist in the namespace "http://Gu.com/Units".

XAML中的显式名称空间声明—即具有xmlns:units="clr-namespace:Gu.Units;assembly=Gu.Units"—工作正常,但我也想避免这种情况.

An explicit namespace declaration in the XAML — i.e. having xmlns:units="clr-namespace:Gu.Units;assembly=Gu.Units" — works fine but I would also like to avoid that.

有没有一种方法可以让我的Gu.Units.Wpf.dll程序集提供必要的[XmlnsDefinition]属性,以映射Gu.Units.dll程序集的名称空间,因此后者本身不需要引用System.Xaml.dll,也可以根本没有任何XAML专用代码?

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?

推荐答案

如果我正确理解,您的问题可以归结为:

If I understand correctly, your question boils down to this:

具有xmlns:units="clr-namespace:Gu.Units;assembly=Gu.Units"效果很好,但这是我要避免的事情.

Having xmlns:units="clr-namespace:Gu.Units;assembly=Gu.Units" works fine but it is what I'm trying to avoid.

有没有办法做到这一点?

Is there a way to do this?

答案:不,没有任何方法可以避免声明 some XML名称空间前缀.

The answer: no, there is not any way to avoid declaring some XML namespace prefix.

  1. [XmlnsPrefix]属性对手动创作的XAML无效. IE.它确实没有在XAML的范围内引入xmlns前缀.它只是XAML创作工具可以检索的标记,因此,当它们自动生成XAML声明时,它们就可以选择要使用的xmlns前缀.例如.如果使用VS Designer从引用的库中添加新对象,则可以在该库中查找以了解将对象添加到XAML时,需要将适当的xmlns:属性添加到外部容器元素,并且在添加对象的XAML中使用指定的前缀.

  2. 这些属性都不会对在指定属性的同一程序集中创作的XAML产生任何影响.这些属性仅在完全编译的程序集中才有用,当然,只有在程序集中的XAML编译完成后,您才能使用这些属性.这样XAML不能使用属性.

  3. 在由包含当前正在编辑的XAML的程序集所引用的程序集中指定时,保留[XmlnsDefinition]属性.在这种情况下,该属性很有用,但仍然不允许您放弃xmlns:属性声明.相反,它的作用是允许您将URI(例如http://Gu.com/Units)映射到一个或多个CLR名称空间.这样,单个xmlns:前缀属性声明可以 a)引用多个CLR命名空间,而 b)这样做无需编写XAML实际专门为任何CLR名称空间命名(即,它封装了程序集引用的托管代码方面,将其隐藏在URI后面).

    这样,您可以编写xmlns:units="http://Gu.com/Units"而不是编写xmlns:units="clr-namespace:Gu.Units;assembly=Gu.Units",这将允许units xmlns前缀限定通过http://Gu.com/Units URI的任何CLR名称空间中的任何类型. >属性.

    但是您仍然必须声明XML名称空间前缀.只是声明采用了与其他方式不同的形式.
  1. The [XmlnsPrefix] attribute has no effect on manually-authored XAML. I.e. it does not introduce an xmlns prefix to the scope of the 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. E.g. 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.

  2. Neither of these attributes have any effect on XAML authored in the same assembly in which the attributes are specified. 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. So that XAML can't use the attributes.

  3. That leaves the [XmlnsDefinition] attribute, when specified in an assembly that is referenced by the assembly containing the XAML currently being edited. In this scenario, the attribute is useful but still does not allow you to forego the xmlns: attribute declaration. Instead what it does is allows you to map a URI (e.g. http://Gu.com/Units) to one or more CLR namespaces. 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 (i.e. it encapsulates the managed-code aspect of the assembly reference, hiding that behind a 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.

    But you still have to declare the XML namespace prefix. It's just that the declaration takes a different form than would otherwise be needed.


注意::当多个程序集使用[XmlnsDefinition]属性在彼此相同的URI中声明CLR名称空间时,所有名称空间均由XAML中的URI引用,该URI引用了所有这些程序集.您可以利用此功能将您自己的库的命名空间与您希望在XAML中已被引用的URI的命名空间结合起来(例如http://schemas.microsoft.com/winfx/2006/xaml/presentation).


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. 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 (e.g. http://schemas.microsoft.com/winfx/2006/xaml/presentation).

只要创作工具在XAML中发出的xmlns:属性中实际上使用了URI,就可以解决"您所要解决的问题.但是,将您自己的程序集命名空间与框架中预先存在的程序集命名空间相结合是一个骇人且明智的选择.即使没有类型名称冲突,也仍然是一种不好的做法,当然,如果存在类型名称冲突,可能会导致严重的问题.

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. 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.


根据您的评论:

我要解决的问题是将Gu.Units加入 http://Gu.com/Units无需添加对Gu.Units的System.Xaml的引用

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

来自文档:

将一个或多个XmlnsDefinitionAttribute属性应用于程序集,以便标识程序集内的类型以供XAML使用. [强调我的]

Apply one or more XmlnsDefinitionAttribute attributes to assemblies in order to identify the types within the assembly for XAML usage. [emphasis mine]

即您只能使用[XmlnsDefinition]映射给定名称空间中的类型,这些类型实际上是在指定属性本身的同一程序集中声明的.

I.e. 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.

该属性包括一个AssemblyName属性,该属性似乎表示您可以包括其他程序集的类型.这是文档的自然阅读,并且可能是该属性的使用目的.不幸的是,该框架无法控制其他代码如何使用该属性,而XAML工具实际上忽略了该属性.

The attribute includes an AssemblyName property, which seems to indicate you could include types from other assemblies. 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.

[XmlnsDefinition]属性只能用于将URI映射到在找到该属性的程序集中声明的名称空间.您可以指定其他程序集名称,但是Visual中的XAML设计器和编译器. Studio不会注意AssemblyName属性.

The [XmlnsDefinition] attribute can be used only to map URIs to namespaces declared in the assembly in which the attribute is found. You can specify other assembly names, but the XAML designer and compiler in Visual Studio pay no attention to the AssemblyName property.

WPF团队已确认这是一个错误,但已声明他们不会解决问题.

The WPF team has acknowledged this to be a bug, but has stated that they will not fix the problem.


可以逐个解决该问题.最明显的方法是在指定了[XmlnsDefinition]的程序集中声明一个新类型,并从另一个程序集中继承所需的类型.例如,在您的Gu.Units.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. For example, in your Gu.Units.Wpf assembly, you could declare a type like this:

public class LengthUnits : Gu.Units.LengthUnits { }

然后您将使用类型Gu.Units.Wpf.LengthUnits而不是Gu.Units.LengthUnits结束.显然,这仅在类型是未密封的引用类型时才有效.另外,根据类型的实际使用方式,您可能会遇到一些问题,例如代码尝试使用Gu.Units.LengthUnits的实例,而其中需要Gu.Units.Wpf.LengthUnits的实例.对于简单的单向绑定方案,可能不会出现这种情况,但我可以轻松想象其他方案.

Then you would wind up using the type Gu.Units.Wpf.LengthUnits instead of 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. For simple one-way binding scenarios, this probably wouldn't come up but I can easily imagine other scenarios where it would.

解决此问题的较不明显的方法是使用[TypeForwardedTo]属性.例如,在您的Gu.Units.Wpf程序集中,您可以包括以下内容:

A less obvious way to work around the problem is to use the [TypeForwardedTo] attribute. For example, in your Gu.Units.Wpf assembly, you could include this:

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

其优点是所讨论的类型将是相同类型.但是,这是运行时的效果,在XAML设计器工具中不能很好地发挥作用.您的项目将正确构建并运行,但是设计人员仍会抱怨未找到类型'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. Your project will build and run correctly, but the designer will still complain that "the type 'units:LengthUnits' was not found".

我不知道有任何解决方法可以在命名空间的基础上更广泛地解决该问题.

I am not aware of any work-around that will address the issue more broadly, on a namespace basis.

这篇关于如何在XAML中的CLR命名空间中从声明的程序集以外的程序集映射类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆