我正在研究windows store app中的棱镜。我遇到了问题。我有很多观点,我想将它们分成不同的文件夹。但问题是NavigationService无法找到它们。说明书说所有的视图显示放入views文件夹,然后导航服务可以使用navigationservice.navigate(“main”,null)导航到它们,但是如果视图不在导航服务找不到它们的views文件夹的根目录
答案 0 :(得分:5)
NavigationService根据约定查找Views和ViewModels。所有视图必须位于"视图"文件夹和ViewModel必须位于" ViewModels"夹。如果id不适合您,可以执行以下操作:
将以下类添加到项目中:
public class ViewViewModelTypeResolver
{
private const string ViewNameSuffix = "Page"; // You can change this View name suffix
private const string ViewModelNameSuffix = "ViewModel"; // You can change this ViewModel name suffix
private readonly Lazy<Dictionary<string, Type>> _uiAssemblyExportedTypes;
private Dictionary<string, Type> UiAssemblyExportedTypes
{
get { return _uiAssemblyExportedTypes.Value; }
}
public ViewViewModelTypeResolver(Type typeFromUiAssembly)
{
_uiAssemblyExportedTypes = new Lazy<Dictionary<string, Type>>(() => GetUiAssemblyExportedTypes(typeFromUiAssembly));
}
public Type GetViewType(string viewTypeName)
{
return UiAssemblyExportedTypes[viewTypeName];
}
public Type GetViewModelType(Type viewType)
{
var pageNameWithoutSuffix = viewType.Name.Remove(viewType.Name.LastIndexOf(ViewNameSuffix, StringComparison.Ordinal));
var viewModelName = String.Concat(pageNameWithoutSuffix, ViewModelNameSuffix);
return UiAssemblyExportedTypes[viewModelName];
}
private static Dictionary<string, Type> GetUiAssemblyExportedTypes(Type typeFromUiAssembly)
{
return typeFromUiAssembly.GetTypeInfo().Assembly.ExportedTypes.ToDictionary(type => type.Name, type => type, StringComparer.Ordinal);
}
}
将ViewViewModelTypeResolver添加到App构造函数:
public App()
{
var mainPage = typeof(MainPage); // Any of pages from your solution. Pay attention that the resolver will be able to resolve Views and ViewModels that locates in the same project as specified page.
_viewViewModelTypeResolver = new ViewViewModelTypeResolver(mainPage);
}
当您使用Prism时,我假设您从MvvmAppBase
继承了您的App类。如果是这样,您应该覆盖GetPageType
方法:
protected override Type GetPageType(string pageToken)
{
return _viewViewModelTypeResolver.GetViewType(pageToken);
}
然后在SetDefaultViewTypeToViewModelTypeResolver
方法中添加OnInitializeAsync
:
protected override async Task OnInitializeAsync(IActivatedEventArgs args)
{
// Your initialization code
ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver(GetViewModelType);
// Your initialization code
}
private Type GetViewModelType(Type pageType)
{
return _viewViewModelTypeResolver.GetViewModelType(pageType);
}
现在您可以导航到任何页面,即使它们被分成不同的文件夹。
答案 1 :(得分:0)
Alexander.Ermolaev的精彩回答。我想扩展他的班级以满足我的需要。我不喜欢公开我的所有ViewModel。当我们真正需要的是Views和ViewModel的类型时,我也不想保留所有类型的字典。这将找到从UserControl继承的所有视图,因为ViewModelLocator将与UserControls以及Pages一起使用。这将找到从基本视图模型类继承的所有ViewModel,通常是Prism的ViewModelBase。
sealed class ViewViewModelTypeResolver
{
private readonly Assembly _assembly;
private readonly Type _baseViewModelType;
private readonly string _viewNameSuffix;
private readonly string _viewModelNameSuffix;
private readonly Lazy<Dictionary<string, Type>> _views;
private readonly Lazy<Dictionary<string, Type>> _viewModels;
private Dictionary<string, Type> Views => _views.Value;
private Dictionary<string, Type> ViewModels => _viewModels.Value;
/// <summary>
/// Resolves Views and ViewModels.
/// </summary>
/// <param name="typeFromUiAssembly">Use any type from the UI Assembly.</param>
/// <param name="baseViewModelType">All view models need to inherit from this type.</param>
/// <param name="viewNameSuffix">Prism convention is to name your views with a Page suffix.</param>
/// <param name="viewModelNameSuffix">Prism convention is name your viewmodels with a ViewModel suffix.</param>
public ViewViewModelTypeResolver(Type typeFromUiAssembly, Type baseViewModelType, string viewNameSuffix = "Page", string viewModelNameSuffix = "ViewModel")
{
_baseViewModelType = baseViewModelType;
_viewNameSuffix = viewNameSuffix;
_viewModelNameSuffix = viewModelNameSuffix;
_assembly = typeFromUiAssembly.GetTypeInfo().Assembly;
_views = new Lazy<Dictionary<string, Type>>(GetViews);
_viewModels = new Lazy<Dictionary<string, Type>>(GetViewModels);
}
/// <summary>
/// Gets a View type for the given name.
/// </summary>
/// <param name="viewTypeName">Name of the view without the suffix.</param>
public Type GetViewType(string viewTypeName)
{
var pageName = string.Concat(viewTypeName, _viewNameSuffix);
return this.Views[pageName];
}
/// <summary>
/// Gets a ViewModel for the given view type.
/// </summary>
/// <param name="viewType">Type of view.</param>
public Type GetViewModelType(Type viewType)
{
var viewModelName = string.Concat(viewType.Name, _viewModelNameSuffix);
return this.ViewModels[viewModelName];
}
/// <summary>
/// Gets all the View types by finding all types that inherit from Page and are defined in the UI Assembly.
/// </summary>
private Dictionary<string, Type> GetViews()
{
var types = _assembly.DefinedTypes.Where(type => !type.IsAbstract && type.IsSubclassOf(typeof(UserControl)));
return types.ToDictionary(typeInfo => typeInfo.Name, typeInfo => typeInfo.AsType(), StringComparer.Ordinal);
}
/// <summary>
/// Gets all the ViewModel types by finding all types that inherit from a base ViewModel type defined in the UI Assembly.
/// </summary>
private Dictionary<string, Type> GetViewModels()
{
var types = _assembly.DefinedTypes.Where(type => !type.IsAbstract && type.IsSubclassOf(_baseViewModelType));
return types.ToDictionary(typeInfo => typeInfo.Name, typeInfo => typeInfo.AsType(), StringComparer.Ordinal);
}
}
App.cs中的用法:
private readonly ViewViewModelTypeResolver _viewViewModelTypeResolver;
public App()
{
this.InitializeComponent();
_viewViewModelTypeResolver = new ViewViewModelTypeResolver(this.GetType(), typeof(ViewModelBase));
}
//other methods are the same as Alexander's answer.
感谢Alexander,您的代码对我来说是一个很好的起点。