Navigation for Win Phone 8

Topics: Bugs
Dec 13, 2012 at 12:54 PM

I'm running into problems with navigation on WinPhone 8. When I do the following:

_navigation.UriFor<MyViewModel>().WithParam(vm => vm.Id, 1).Navigate();

An ArgumentException is thrown in Microsoft.Phone.ni.dll with the message "Navigation is only supported to relative URIs that are fragments, or begin with '/', or which contain ';component/'.Parameter name: uri"

It seems to me that the URL that is generated by UriFor<>() should begin with a '/', but it does not. Is this a bug in Caliburn Micro or am I doing something wrong?

Dec 13, 2012 at 8:22 PM

The problem was that the assembly name of my assembly didn't match the name of the namespace for my views, which caused the URL that was generated by UriFor<>() to be wrong. This seems like a bug, unfortunately not one that I know how to fix. The solution for me was to rename my assembly and now everything works fine.

Dec 14, 2012 at 1:36 AM

This might be caused by the assembly name and namespace needing to match issue that came with the VS 2012 Update #1. I had to fix our code the other day for this issue when I updated the VS 2012 Update #1. Look at the <xyz>.g.cs file generated from your xaml in the obj folder and you can see what it's looking for. We were getting XamlParseExceptions in our code that isn't using Caliburn. A previous issue from CP to RTM was having a period in the name that caused a XamlParseException. That was fixed by not using periods or using underscores and MS had a hotfix as well.

Dec 14, 2012 at 8:50 AM

It seems like ViewLocator.DeterminePackUriFromType is the culprit. It assumes that the name of the assembly and the namespace matches, which is what you're describing but I'm not sure it has anything to do with Visual Studio version?

Mar 14, 2013 at 3:39 PM
Mar 20, 2013 at 9:01 PM
Sorry, but this change will not work if the view is in a sub-namespace/folder.
You can verify this with the latest HelloWP71 sample application.

DeterminePackUriFromType is a delegate so you can change it in your project if you need it.
Set it in your bootstrappers Configure() method:
ViewLocator.DeterminePackUriFromType = (viewModelType, viewType) => {
   var assemblyName = viewType.Assembly.GetAssemblyName();
   var uri = viewType.FullName.Replace(assemblyName, string.Empty).Replace(".", "/") + ".xaml";

   if(!Application.Current.GetType().Assembly.GetAssemblyName().Equals(assemblyName)) {
      return "/" + assemblyName + ";component" + uri;
   }

   return uri;
};