我有一个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中执行此操作。
答案 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
一个视图模型然后在活页夹启动时解析视图,但是如果我的假设是正确的,它应该可以工作