FreshMvvm
FreshMvvm copied to clipboard
Resolve Pages from different assemblies than the PageModel
Currently, the FreshPageModelResolver
resolves Pages only from the same assembly as the PageModel. That implies that when having PageModels and Pages in different projects for example, resolution of the Page fails.
// Fails when MainPage lives in a different assembly than MainPageModel
var page = FreshPageModelResolver.ResolvePageModel<MainPageModel>();
Why would I want that?
Personally, I like to have PageModels and Pages in different projects. I share PageModels across all frontend technologies (Xamarin.Forms for iOS and Android, Xamarin.Mac and UWP without Xamarin.Forms). Although all these projects might structure their pages differently that can all use the same PageModel. So I have a MyProject.Frontend.Shared
project for my PageModels and reference that form MyProject.Frontend.Forms.iOS
, MyProject.Frontend.UWP
, ... and so on.
How to solve that today
Fortunately, FreshMVVM is very easy to extend so that I simply wrote my own PageModelMapper
class that takes an alternative assembly and namespace as parameters.
public class MyFreshPageModelMapper : IFreshPageModelMapper
{
readonly string pageNamespace;
readonly string pageAssemblyName;
public MyFreshPageModelMapper(string pageNamespace = null, string pageAssemblyName = null)
{
this.pageNamespace = pageNamespace;
this.pageAssemblyName = pageAssemblyName;
}
public string GetPageTypeName(Type pageModelType)
{
var assemblyQualifiedName = pageModelType.AssemblyQualifiedName;
// Replace Namespace
if (pageNamespace != null)
assemblyQualifiedName = assemblyQualifiedName.Replace(pageModelType.Namespace, pageNamespace);
// Replace Assembly
if (pageAssemblyName != null)
assemblyQualifiedName = assemblyQualifiedName.Replace(pageModelType.Assembly.ToString(), pageAssemblyName);
// Replace "Model"
assemblyQualifiedName = assemblyQualifiedName
.Replace("PageModel", "Page")
.Replace("ViewModel", "Page");
return assemblyQualifiedName;
}
}
With that, I can easily call the following before I resolve any Page with FreshMvvm.
// Configure FreshPageModelResolver to resolve Pages
// from different Namespaces/Assemblies than the ViewModel
FreshPageModelResolver.PageModelMapper =
new MyFreshPageModelMapper(
typeof(MainPage).Namespace,
typeof(MainPage).Assembly.ToString());
What I propose
I would love to see the default PageModelMapper
getting extended by the configuration I have shown above to become more flexible when resolving Pages.
I am more than happy to submit a Pull Request for this but first wanted to hear what you guys think!
This is a great idea. What are the alternatives if you want your pages and pagemodels in separate projects?
@Hammurabidoug The current workaround is what I described above.
@robinmanuelthiel Yeah. I tried it and it didn't work. We'll try to look again at some point.
Works for me! I used it here, if you want to take a look: https://github.com/MikeCodesDotNet/Mobile-Cloud-Workshop/blob/master/Mobile/ContosoFieldService.Core/Helpers/PageModelLocator.cs
@robinmanuelthiel nice addition! I too had struggled with resolving my "Views" and "ViewModels" but built my own IFreshPageModelMapper so that I could keep my Views in the Views folder/namespace and my ViewModels in my ViewModels folder/namespace. Call me crazy... but isn't MVVM supposed to be about Models, Views, and ViewModels? It's not called MPPM, so I'm confused where this lingo came from and why it persists. Regardless, I'm really liking FreshMvvm so far, so I'm willing to ignore that it violates my own personal version of naming logic. Thanks for sharing your code.
@mpalmer78 You are correct, the whole "PageModel" thing annoys me as well. But luckily, you can also call your classes "ViewModels" like MyCoolViewModel
and FreshMVVM will find them as well, as described here: https://github.com/rid00z/FreshMvvm#conventions
Yes, I read that section on the conventions but in practice I did not find it to be the case. FreshMvvm was not able to resolve my ViewModels or Views that were contained within respective ViewModels/Views namespaces. I had to implement my own IFreshPageModelMapper in order to properly resolve my types. Regardless, I'm glad the ability to build my own mapper is available in FreshMvvm.
If the ViewModel and View are in the same assembly, MyTestPage
should resolve MyTestViewModel
. And MyTestView
should also resolve MyTestViewModel
.
I couldn't make the View/ViewModel convention, which is the correct one if you ask me and the OCD in me cannot live with this Page/PageModel thing - so totally agree with @mpalmer78
I solved it simply by creating this little PageModelMapper:
public class MvvmConventionPageModelMapper : IFreshPageModelMapper
{
public string GetPageTypeName(Type pageModelType)
{
return pageModelType.AssemblyQualifiedName.Replace("ViewModel", "View");
}
}
And then you just set it in the App.xaml.cs as part of your IoC setup, something like this:
public App()
{
InitializeComponent();
InitializeDependencies();
var homeView = FreshPageModelResolver.ResolvePageModel<HomeViewModel>();
var mainNavigation = new FreshNavigationContainer(homeView);
MainPage = mainNavigation;
}
private void InitializeDependencies()
{
FreshPageModelResolver.PageModelMapper = new MvvmConventionPageModelMapper();
FreshIOC.Container.Register<IYouTubeService, YoutubeService>();
}
that is seriously needs to be implemented this will help to work with Tizen also. Tizen implements a CirclePage which is inherited from ContentPage but since it uses different namespace it is impossible to use freshmvvm. thats why this is very important.
Hey
We can already do this, I will write up some content but basically there’s a interface that you can implement to control the resolution.
On Sat, 31 Aug 2019 at 12:41 pm, Emil Alipiev [email protected] wrote:
that is seriously needs to be implemented this will help to work with Tizen also. Tizen implements a CirclePage which is inherited from ContentPage but since it uses different namespace it is impossible to use freshmvvm. thats why this is very important.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/rid00z/FreshMvvm/issues/218?email_source=notifications&email_token=AALZPPIILCSCFHYSZ2LQGOTQHHK6LA5CNFSM4ESH5VIKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD5TDTVA#issuecomment-526793172, or mute the thread https://github.com/notifications/unsubscribe-auth/AALZPPN5JFKKHJOBZLBV65LQHHK6LANCNFSM4ESH5VIA .
--
[image: XAM-Consulting Pty Ltd] http://www.xam-consulting.com/
[image: Twitter] https://twitter.com/XAMConsulting [image: LinkedIn] https://www.linkedin.com/company-beta/5791295/
Michael Ridland / Director / Xamarin & Microsoft MVP [email protected] / 0404 865 350
XAM Consulting Pty. Limited. Web | Cloud | Apps | Xamarin 210/29 Kiora Rd, Miranda NSW 2228 xam-consulting.com http://www.xam-consulting.com/
Hi @rid00z
would you mind sharing more information or if you posted somewhere else? thanks a lot
@robinmanuelthiel is your code not slow? are you doing this once when your application is loaded or everytime you navigate to a viewmodel?