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:
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.Is there a way to do this?
The answer: no, there is not any way to avoid declaring some XML namespace prefix.
[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.[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).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.
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
).
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.
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
From the documentation:
Apply one or more XmlnsDefinitionAttribute attributes to assemblies in order to identify the types within the assembly for XAML usage. [emphasis mine]
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.
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.
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.
The WPF team has acknowledged this to be a bug, but has stated that they will not fix the problem.
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 { }
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.
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))]
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.