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