At first I was going title this post Creating a Xamarin.Forms Shared Project App? Do This First! And the contents of that post were going to solve one of the problems that every developer faces when creating a Forms application using shared projects. Namely, that of referencing custom controls created in the shared project within XAML when running under both iOS and Android. Not too complicated a subject, as it’s a very easy fix … but as you may have guessed by the original title of the post – I have a tendency to forget to “implement the solution” right away. I figured by writing it down, I would never forget again – saving myself a moment of “what the ???” later.
But then this morning (about an hour ago as I type this) I found that the new Xamarin Studio 6 gives a workaround / solution to this … by default! Instead of having that let me off the hook and not writing at all – I still wanted to outline the problem and the quick solutions – both the one I was using and the one Xamarin Studio 6 provides.
The Problem
Whether you need to extend one of the built-in Xamarin.Forms controls, or create a brand new one altogether, an app of sufficient complexity will call for a custom control at some point. Once the control is built, in order to use it, you need to reference it in your XAML page. In order to do so, the following line is added to the XML attribute section for the content page or view: xmlns:local=”clr-namespace:DoThisFirst;assembly=DoThisFirst”
The clr-namespace
specifies the namespace of where the control can be found, and the assembly
is the DLL or EXE.
Pretty easy & simple.
Except when one is using a shared project. Shared projects do not emit a separate assembly when compiled (I’ve written about them previously, here and here). Instead the code is directly compiled into the platform project’s assembly.
Great, what’s the issue?
By default, when creating a new solution with Xamarin Studio, the assembly names that are emitted for iOS and Android are named differently. In the case of our “DoThisFirst” project, the assembly names are “DoThisFirst.iOS” and “DoThisFirst.Droid”.
This means that we’re not able to use the following any longer, as it will not work across both platforms (or in this case neither) at the same time: xmlns:local=”clr-namespace:DoThisFirst;assembly=DoThisFirst”
The assembly running the code “DoThisFirst.iOS” or “DoThisFirst.Droid” do not match up with the “assembly” portion of the line above … a run time error (or compile time if XAML compilation is turned on) will occur. It’ll be a System.IO.FileNotFoundException
.
How To Fix It?
Super, super simple. Change the output assembly’s name in both the Droid’s & iOS’ project options to be the same thing. This is done in Xamarin Studio through the project options -> build -> output node. And on iOS, make sure you do it for both the simulator & device platforms.
Because if you would ever happen to ship an IPA off for testing without first running it on device, and the output name wasn’t correct – it’ll crash – and that would be embarrassing. Not that you would do that … but somebody might (as I look around nervously).
There’s also another way to fix this issue, and it’s the way I alluded to earlier in this post. That’s by omitting the assembly attribute from the declaration altogether. So it would now look like: xmlns:local=”clr-namespace:DoThisFirst”
. Xamarin Studio now creates this attribute for you when creating a new XAML content page, and to be honest, I didn’t know one could only declare the namespace and not the assembly. Pretty cool.
To be honest, I still prefer to specifically call out the assembly in addition to the namespace in the declaration, only if to be completely clear. But I was happily surprised to see the local namespace was added by default.
New content page XAML template in #xamarin studio now specifies the local namespace by default, now I can use those 100 keystrokes to tweet!
— Matthew Soucoup (@CodeMillMatt) June 22, 2016
In Summary
Change those output assembly names when working with Xamarin.Forms shared projects! It’ll save you some headaches when working with custom controls. It will also make life easier if you ever need to start messing around with System.Reflection.Assembly
and all the goodness that it supplies.
Comments