棱镜如何在视图文件夹的子文件夹中找到视图

时间:2014-09-23 02:39:58

标签: c# .net wpf windows-store-apps prism

我正在研究windows store app中的棱镜。我遇到了问题。我有很多观点,我想将它们分成不同的文件夹。但问题是NavigationService无法找到它们。说明书说所有的视图显示放入views文件夹,然后导航服务可以使用navigationservice.navigate(“main”,null)导航到它们,但是如果视图不在导航服务找不到它们的views文件夹的根目录

2 个答案:

答案 0 :(得分:5)

NavigationService根据约定查找Views和ViewModels。所有视图必须位于"视图"文件夹和ViewModel必须位于" ViewModels"夹。如果id不适合您,可以执行以下操作:

  1. 将以下类添加到项目中:

    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);
        }
    }
    
  2. 将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);
    }
    
  3. 当您使用Prism时,我假设您从MvvmAppBase继承了您的App类。如果是这样,您应该覆盖GetPageType方法:

        protected override Type GetPageType(string pageToken)
        {
            return _viewViewModelTypeResolver.GetViewType(pageToken);
        }
    
  4. 然后在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);
    }
    
  5. 现在您可以导航到任何页面,即使它们被分成不同的文件夹。

答案 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,您的代码对我来说是一个很好的起点。