在Windows Phone 8.1中使用Caliburn.Micro为多个ViewModel使用单一视图

5
我有一个使用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。

应用程序导航到正确的View,但ViewModel从未被创建。有点像Caliburn.Micro忘记了ViewModel,或者使用不同的约定查找ViewModel之类的东西。

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

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

有任何想法如何解决这个问题吗?

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

1个回答

0
这种解决方案在除顶级导航之外的任何地方都可以工作。原因是当您导航时,有一种“双重分派”正在进行。
正如您所知,FramePhoneNavigationFrame控件(取决于WinRT还是Silverlight)在其导航中是基于视图的。因此,步骤看起来有点像这样:
  1. 您的代码告诉导航服务导航到ProductViewModel
  2. 它使用ViewLocator(其中您已注入了代码)来定位ProductView并告诉Frame导航到该视图。
  3. 然后,导航服务响应导航事件到ProductView并使用ViewModelLocator定位正确的视图模型。
  4. 然后实例化和绑定此视图模型。
导航服务中的这种视图模型到视图到视图模型的步骤会导致您的代码出现问题。
您应该能够创建简单继承基本视图且不添加任何内容的虚拟视图。因此,如果您有MySharedView.xaml,则声明以下内容应该就足够了。

public class SecondView : MySharedView { }

我知道这不是理想的方法,但它确实可以让你获得所需的重用性。让导航服务在导航事件之间记住视图模型会变得非常复杂,因为还有很多外部因素可能会引起导航。


是的,我尝试在导航和ViewModel解析之间记住ViewModel类型,它起作用了,但似乎有些hacky和有风险。你的解决方案看起来很合理,谢谢。 - Igor Kulman
出现了一个“System.TypeLoadException”类型的异常,但在用户代码中未被处理,该异常发生在“Caliburn.Micro.Platform.DLL”中。附加信息:无法找到Windows Runtime类型“Windows.Foundation”。我已更新示例:https://dl.dropboxusercontent.com/u/73642/CMVMTest.zip - Igor Kulman
目前我也看到了一个错误,但是它是一个访问冲突异常。我会进一步深入挖掘。 - Nigel Sampson
我遇到了相同的错误,但是在尝试实现Deep Linking时(即我的自定义协议启动应用程序)。App.OnActivate()重写被调用,绕过了通常的引导过程。我强制执行Initialize(),这似乎启动了IOC等,但是当我使用navigationService.Navigate<MyViewModel>()进行导航时,我会收到这个异常。 - RogerW
一些反馈。我发现在App.OnActivate()上使用DisplayRootView<MyViewModel>()是有效的。我不再收到“找不到Windows Runtime类型'Windows.Foundation'”的异常。 - RogerW

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接