Caliburn Micro WinRT导航和导体

时间:2012-12-05 16:13:44

标签: c# windows-runtime winrt-xaml caliburn.micro

我有一个WinRT应用程序,使用caliburn.micro INavigationService(FrameAdapter)启动并运行良好。问题是我的应用程序中的所有页面都是完整页面,并且它们重复了很多视图xaml标记。我想要做的是拥有更多的“MasterPages”类型的架构,其中我有一个shell视图,它定义了主要布局并包含ContentControl并使用Conductor模式来切换ContentControl的内容。我以前使用WPF和Silverlight在这种架构上取得了成功,所以我认为它可以在WinRT中使用。

问题是导航基础设施(使用FrameAdapter)和使用绑定到导体ActiveItem的ContentControl(如SimpleNavigation样本)的Conductor基础设施之间似乎断开连接。

在导体场景中,我使用ActivateItem:

ActivateItem(new MyViewModel());

但是使用INAVigationService我使用NavigateToViewModel:

navigationService.NavigteToViewModel<MyViewModel>();

,据我所知,这两者似乎没有联系。

我的一个想法是创建一个实现INavigationService的ConductorNavigationService,并基本上处理子屏幕的创建和激活。虽然它看起来似乎不太直接,但我想我会检查是否有一种已经支持的方法在caliburn.micro中执行此操作。

1 个答案:

答案 0 :(得分:3)

好的,我的理解可能有点紧张,因为我没有使用WinRT或INavigationService,但我认为Frame是RT的一部分,INavigationService提供了视图模型的分辨率和导航帧。

我的另一个假设是你的框架有点像你的指挥,当你在框架上调用'Navigate()'时,它只是用新指定的内容替换框架的内容。如果是这种情况,则CM正在查看视图模型的第一个分辨率。

由于你想要去指挥路线,听起来你想放弃INavigationService的CM实现,只是自己动手来处理INavigationService导航方法(例如跳过{{1 s Frame方法)。

快速浏览一下CM来源,发现所有Navigate()正在处理框架上的NavigationService事件,然后进行VM解析并设置视图(导体可能已经做过的事情) 。您需要做的就是确保您的Navigate实现只是将指定的视图加载到shell中而不是导航框架

您可能只需要窃取INavigationService的构造函数代码并更改NavigationService的实现,然后在shell上调用Navigate(),其中x是VM的实例。 CM将负责其余的事情(我认为CM boostrapper已经设置了你的root'Frame',所以你不必担心这个。)

e.g。

实现可能看起来更像这样(请记住,这只是我扔在一起的东西,可能是赤裸裸的谎言!):

ActivateItem(x)

以自己的方式滚动它应该不会太困难。这对你有帮助吗?

然后你的XAML会非常简单:

public class NewFrameAdapter : INavigationService
{
    private readonly Frame frame;
    private readonly IConductActiveItem shell;
    private event NavigatingCancelEventHandler ExternalNavigatingHandler = delegate { };

    public NewFrameAdapter(Frame frame)
    {
        this.frame = frame;

        // Might want to tighten this up as it makes assumptions :)
        this.shell = (frame as FrameworkElement).DataContext as IConductActiveItem;
    }

    public bool Navigate(Type pageType)
    {
        // Do guardclose and deactivate stuff here by looking at shell.ActiveItem
        // e.g.
        var guard = shell.ActiveItem as IGuardClose;

        if (guard != null)
        {
            var shouldCancel = false;
            guard.CanClose(result => { shouldCancel = !result; });

            if (shouldCancel)
            {
                e.Cancel = true;
                return;
            }
        }

        // etc

        // Obviously since the guard is probably async (assume it is, if not you are ok to continue!) you'd have to not call this code right 
        // here but I've just stuck it in here as an example

        // edit: looking at the code above (the guard code) it looks like this is all sync so the below code should be fine

        // You might get away with calling shell.ActivateItem(pageType) as I'm not sure
        // if the viewmodel binder in RT would resolve this all for you, but if it doesnt...

        // Init the view and then resolve the VM type
        ViewLocator.InitializeComponent(pageType);

        var viewModel = ViewModelLocator.LocateForView(pageType);

        // Activate the VM in the shell)
        shell.ActivateItem(viewModel);
    }

我认为这可能是view-first和viewmodel-first的混合,因为你的根<Frame blah blah> <SomeStaticContent /> <ContentControl x:Name="ActiveItem" /> <!-- The dynamic bit... --> <SomeMoreStaticContent /> </Frame> 将使用view-first,你的指挥将使用Frame一个视图模型然后在活页夹启动时解析视图,但是如果我的假设是正确的,它应该可以工作