I have a Windows Phone 8.1 app using Caliburn.Micro. In the app I have a few ViewModels that fetch data in different way and with different logic but show them in the same way. So I want to make all those ViewModel use the same one View.
I found out that ViewLocator.LocateTypeForModelType
is a method that gets executed for mapping ViewModels to Views. So I override it to use my custom attribute when present:
var original = ViewLocator.LocateTypeForModelType;
ViewLocator.LocateTypeForModelType = (modelType, displayLocation, context) =>
{
var useViewAttributes = modelType.GetTypeInfo().GetCustomAttributes<UseViewAttribute>(true);
if (useViewAttributes.Count() == 1)
{
var viewTypeName = string.Concat(modelType.Namespace.Replace("Model", string.Empty), ".", useViewAttributes.First().ViewName);
var type = AssemblySource.FindTypeByNames(new List<string>() { viewTypeName });
return type;
}
return original(modelType, displayLocation, context);
};
Stepping through the it seems to work fine. If I navigate to a ViewModel and that ViewModel has a UseView, my method returs the correct View.
The app navigates to the correct View but the ViewModel is never created. Kind of like Caliburn.Micro forgot about the ViewModel, or was looking for one using a different convention, or something.
I found out that ViewModelLocator.LocateTypeForViewType
is called after navigation to a View to resolve the ViewModel. The ViewModel type from the previous step seems to be forgotten completely.
In ViewModelLocator.LocateTypeForViewType
I only have access to the View type and I do not know, how to make it resolve the correct ViewModel from the previous step. I could scan all the ViewModel and find the ones with the correct attribute, but I would not know which one to choose.
Any ideas on how to approach this?
Here is a minimal project showing my setup: https://dl.dropboxusercontent.com/u/73642/CMVMTest.zip
This sort of solution would work everywhere else except for the top level navigation. The reason for this is there is sort of a "double dispatch: going on when you navigate.
As you know the Frame
or PhoneNavigationFrame
control (depending on WinRT or Silverlight) is view based in it's navigation. So the steps look a little like this.
ProductViewModel
. ViewLocator
(where you've injected your code) to locate ProductView
and tells the Frame
to navigate to that. ProductView
and locates the correct view model using ViewModelLocator
. This sort of view model to view to view model step in navigation service causes the hiccup in your code.
You should be able to create dummy views that simply inherit the base view and add nothing. So if you have MySharedView.xaml
then declaring what's below should be enough.
public class SecondView : MySharedView { }
It's not ideal I know, but does get you the reuse you're after. Having the navigation service remember the view model between the navigating and navigated events becomes complicated with all the external factors that can cause navigation as well.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.