【问题标题】:Using single View for multiple ViewModels with Caliburn.Micro on Windows Phone 8.1在 Windows Phone 8.1 上通过 Caliburn.Micro 对多个 ViewModel 使用单个视图
【发布时间】:2016-03-01 18:43:12
【问题描述】:

我有一个使用 Caliburn.Micro 的 Windows Phone 8.1 应用程序。在应用程序中,我有一些 ViewModel 以不同的方式和不同的逻辑获取数据,但以相同的方式显示它们。所以我想让所有的 ViewModel 使用同一个 View。

我发现ViewLocator.LocateTypeForModelType 是一种用于将 ViewModel 映射到 View 的方法。所以我覆盖它以在存在时使用我的自定义属性:

        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);
        };

单步执行它似乎工作正常。如果我导航到一个 ViewModel 并且该 ViewModel 有一个 UseView,我的方法会返回正确的 View。

应用导航到正确的视图,但从未创建视图模型。有点像 Caliburn.Micro 忘记了 ViewModel,或者正在寻找一个使用不同约定的模型,或者其他什么。

我发现ViewModelLocator.LocateTypeForViewType 在导航到视图以解析视图模型后被调用。上一步中的 ViewModel 类型似乎完全被遗忘了。

ViewModelLocator.LocateTypeForViewType 中,我只能访问 View 类型,我不知道如何使它从上一步中解析正确的 ViewModel。我可以扫描所有 ViewModel 并找到具有正确属性的那些,但我不知道该选择哪一个。

关于如何解决这个问题的任何想法?

这是一个显示我的设置的最小项目:https://dl.dropboxusercontent.com/u/73642/CMVMTest.zip

【问题讨论】:

    标签: c# xaml mvvm windows-phone-8.1 caliburn.micro


    【解决方案1】:

    除了顶级导航之外,这种解决方案适用于其他任何地方。这样做的原因是有一种“双重调度:在您导航时继续。

    如您所知,FramePhoneNavigationFrame 控件(取决于 WinRT 或 Silverlight)是基于其导航的视图。所以步骤看起来有点像这样。

    1. 您的代码告诉导航服务=ce 导航到ProductViewModel
    2. 它使用ViewLocator(您注入代码的位置)定位ProductView,并告诉Frame 导航到该位置。
    3. 然后导航服务将导航事件响应到ProductView 并使用ViewModelLocator 定位正确的视图模型。
    4. 然后实例化并绑定此视图模型。

    这种在导航服务中查看到视图模型步骤的视图模型会导致您的代码出现问题。

    您应该能够创建简单地继承基本视图而不添加任何内容的虚拟视图。所以如果你有MySharedView.xaml,那么声明下面的内容就足够了。

    public class SecondView : MySharedView { }

    我知道这并不理想,但确实可以让您获得所需的重用。让导航服务记住导航和导航事件之间的视图模型变得复杂,因为所有外部因素也会导致导航。

    【讨论】:

    • 是的,我尝试记住导航和 ViewModel 分辨率之间的 ViewModel 类型,它有效,但似乎很笨拙且有风险。您的解决方案似乎很合理,谢谢
    • 获取:Caliburn.Micro.Platform.DLL 中出现“System.TypeLoadException”类型的异常,但未在用户代码中处理其他信息:找不到 Windows 运行时类型“Windows.Foundation”。我更新为示例:dl.dropboxusercontent.com/u/73642/CMVMTest.zip
    • 目前我也看到了一个错误,但这是一个访问冲突异常。将进一步深入研究。
    • 我看到了同样的错误,但在尝试实现深度链接时(即我自己的协议启动应用程序)。 App.OnActivate() 覆盖被调用,绕过通常的引导。我强制执行 Initialise(),这似乎启动了 IOC 等,但是当我使用 navigationService.Navigate() 导航时,我得到了这个异常。
    • 一些反馈。我发现 DisplayRootView() 适用于 App.OnActivate()。我不再收到异常“找不到 Windows 运行时类型'Windows.Foundation'”
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-06
    • 1970-01-01
    • 2015-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多