使用 Calibrun.Micro viewModel-first 方法时如何在设计器中显示 ContentControl?

How to show ContentControl in designer when using Calibrun.Micro viewModel-first approach?

我在采用 ViewModel 优先方法的 WPF 应用程序中使用 Caliburn.Micro (CM)。我正在用一个命令栏和一个活动项目组成主视图。主 viewModel 为命令栏 viewModel 设置 属性,并正确导航到活动项目。

运行时一切正常,问题与设计时有关:主视图在设计器中显示为空,我找不到如何正确设置它。我设法让它在其他场景中工作,例如在设计时为整个 Window 或 UserControl 设置数据上下文时,即当它是 XAML 中的根 UI 元素时。但是现在我无法对 Window.

中的子 ContentPresenter UI 元素执行此操作

这是主视图的节选我正在撰写:

<Window x:Class="...MainView" ...>
  <DockPanel ...>
    <!-- this one binds to a property of type CommandBarViewModel -->
    <ContentControl x:Name="CommandBar" ... />
    <ContentControl x:Name="ActiveItem" ... />
  </DockPanel>
</Window>

我已经检查了一些相关读物,但其中 none 似乎 fit/solve 我的问题。 This question is basically the same as mine, but has no answers. That has a reference to this other question 在我看来,从 cal:View.Model 绑定来看,这是一种视图优先的方法。

我尝试添加如下所示的设计时上下文(fake 命名空间为简洁起见未显示):

<ContentControl x:Name="CommandBar" ... 
   d:DataContext="{d:DesignInstance Type=fake:DesignTimeCommandBarViewModel, IsDesignTimeCreatable=True}" 
   cal:Bind.AtDesignTime="True"/>

但后来我遇到了两种情况之一:

你有什么想法吗?也许这应该通过托管 MainViewModel 的设计时版本来解决?

我检查的其他参考资料:this answer, from Rob Eisenberg himself, this CM thread, this other SO

编辑
根据我最后的(自动)提示,我还尝试创建和实例化一个 DesignTimeMainViewModelnot 继承自 MainViewModel,它公开相同的属性并在其默认构造函数中设置 DesignTimeCommandBarViewModel。在这种情况下,设计人员在命令栏的位置显示了经典的 CM 投诉:找不到 DesignTimeCommandBarViewModel 的视图。 接下来是什么?

好吧,这是我找到的解决方案:我很高兴听到更好的方法或其他建议。

Host MainView XAML 指定指向主视图模型的设计时版本的设计时数据上下文,顺便说一下, 继承自运行时版本MainViewModelContentControl 项保持不变。

<Window x:Class="...MainView" ...
  d:DataContext="{d:DesignInstance Type=fake:DesignTimeMainPanelViewModel, IsDesignTimeCreatable=True}"
  cal:Bind.AtDesignTime="True">

  <DockPanel ...>
    <ContentControl x:Name="CommandBar" ... />
    <ContentControl x:Name="ActiveItem" ... />
  </DockPanel>

</Window>

DesignTimeMainPanelViewModel 具有与 MainPanelViewModel 相同的 public 属性,具有一个没有依赖项的默认 c'tor 及其 c' tor 将 CommandBar 属性 设置为 DesignTimeCommandBarViewModel:

的新实例
public class DesignTimeMainPanelViewModel
{
    public DesignTimeMainPanelViewModel()
    {
        CommandBar = new DesignTimeCommandBarViewModel();
        ActiveItem = ...some instance here as well...;
    }

    public DesignTimeCommandBarViewModel CommandBar { get; private set; }
    public IScreen ActiveItem { get; private set; }
}

DesignTimeCommandBarViewModel class 装饰有一个只有一个必需参数的自定义属性,即 System.Type与该视图模型关联的视图。

在 bootstrap 期间,代码添加了一个新的 ViewLocator 策略,通过设置新的 [ 从视图模型类型获取视图类型=50=].

如果标准定位器函数找不到视图类型,新定位器函数将尝试查找视图类型。当然,它会在视图模型类型上查找自定义属性,如果找到,那将是返回的视图类型。这是要点:

Type viewType = _previousLocate(viewModelType, displayLocation, context);

if (viewType == null)
{
    FakeViewAttribute fakeViewAttr = Attribute.GetCustomAttribute(viewModelType, typeof(FakeViewAttribute)) as FakeViewAttribute;

    if (fakeViewAttr != null) viewType = fakeViewAttr.ViewType;
}

return viewType;