Xamarin.Forms XmlnsDefinition attribute: All of your namespaces become one

When working on a mobile app developed with Xamarin Forms (if  you aren’t, you’re missing all the fun!) you might have your own awesome separate library project of custom controls, effects, behaviors, value-converters, constants:



You’ve might not been very happy (to put it nicely) how you're using your library objects in your app’s XAML, having to deal with all the different XML namespaces and prefixes:


So many prefixes and namespaces to handle! Yikes!

The issue is not just about declaration of prefixes. Having separate prefixes bloats the XAML a lot because you have to use a separate prefix for every object you reference from the corresponding namespace. In my example there are 4 prefixes to deal with!

As a solution to get rid of all the namespaces, a dark thought might have crossed your mind: remove all the CLR namespaces in the library’s code and just have one namespace! But you love your C# namespaces, they give class scope and separation, it’s something you just can’t live without.

With Xamarin.Forms 3.5 released yesterday, there’s a much easier way: the XmlnsDefinition attribute is now public and we can use it in our libraries! Many thanks to the contributor, see the pull-request here https://github.com/xamarin/Xamarin.Forms/pull/2782

Following my example above, with the attribute defined in my library makes my XAML from above to become the following:






Much better! It's just one prefix now: 'mylib'


How to use the attribute

The XmlnsDefinition attribute allows us to define in a mapping between a XML namespace and a CLR namespace defined within the same assembly.

In my library MyLibrary.dll, I define the following mappings:
[assembly: XmlnsDefinition("http://mycompany.com/mylibrary", "MyLibrary.Controls")]
[assembly: XmlnsDefinition("http://mycompany.com/mylibrary", "MyLibrary.Converters")] 

[assembly: XmlnsDefinition("http://mycompany.com/mylibrary", "MyLibrary.Effects")] 

[assembly: XmlnsDefinition("http://mycompany.com/mylibrary", "MyLibrary.Helpers")]

Next, in my "core" project MyApp where I implement my views XAML, I can reference the objects defined in my library by using only one prefix pointing to my namespace:



Using same XML namespace to map to different CLR namespaces allowed me to use only one prefix to access all the library objects defined in different CLR namespaces.

Some few simple things to keep in mind when defining a XmlnsDefinition attribute:
  • The namespace URL can be anything you like, http://mycompany.com/mylibrary is just an example.
  • The XmlnsDefinition is an assembly attribute, so it must be defined at assembly level, outside of any namespace in our code.
  • It must be defined in the “library” assembly (i.e. MyLibrary.dll) not in the assembly referencing the library (i.e. not in Myapp.dll)! 

Where to put all the XmlnsDefinition definitions? They are global per-assembly declarations, so I think AssemblyInfo.cs might be a good place. .NET Standard libraries don’t have it by default, but you can add a file named like that.

We’re not done yet.

After I defined the attributes and referenced the namespace it in XAML, the compilation didn't work, the XAML compiler complained about being unable to find our types:



The error comes because of the linking which is unable to find types which are used by reflection. To fix this, there are few ways, a simple but effective way is to have some dummy code in your MyApp to reference a type from the MyLibrary:



This isn’t very nice, but it does the job.

My suggestion however is to try first without adding the dummy code and the call. Depending on your library, you might be already be calling/referencing stuff from it, so you might not need to do anything.

Comments

Popular posts from this blog

Xamarin Forms: Lazy load the tabs in TabbedPage

Xamarin Forms: Embedding native controls and still have XAML compilation for the Page