WPF Caliburn Micro:使用 ContentControl 在 Window 中动态交换 UserControl

WPF Caliburn Micro: Exchanging UserControls in a Window dynamically using ContentControl

此问题与 Add a usercontrol to caliburm micro dynamically 有关。 在打开这个新线程之前,我已经阅读了任何其他相关线程,但我仍然不明白并且找不到解决方案。如果有人认为这是重复的,请接受我的道歉。

我有一个 window (MainView) 包含 "main" 网格(又名 LayoutRoot)和 2 列。

左栏有 2 个按钮:"Display View 1" 和 "Display View 2"。

我的示例代码包含以下视图和视图模型:

在我的示例代码中,ContentControl 无法识别 UserControl。我究竟做错了什么?如何正确绑定ContentControl?请随时修改我的示例代码。提前谢谢你

MainView.xaml

<Window x:Class="TestCaliMiContentControl.MainView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Main View"
    Width="525"
    Height="350">
    <Grid x:Name="LayoutRoot" ShowGridLines="True">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="30*" />
            <ColumnDefinition Width="100*" />
        </Grid.ColumnDefinitions>
        <StackPanel x:Name="LeftNavPanel" Grid.Column="0">
            <Button x:Name="Display1" Content="Display View 1" />
            <Button x:Name="Display2" Content="Display View 2" />
        </StackPanel>
        <ContentControl x:Name="MainGridContent" Grid.Column="1" />
    </Grid>
</Window>

MainViewModel.cs

public class MainViewModel : PropertyChangedBase
{
    private ContentControl _mainGridContent;
    public ContentControl MainGridContent
    {
        get { return _mainGridContent; }
        set
        {
            _mainGridContent = value;
            NotifyOfPropertyChange(() => MainGridContent);
        }
    }

    public void Display1()
    {
        //MainGridContent = new Display1ViewModel(); // cannot convert source type error
    }

    public void Display2()
    {
        // MainGridContent = new Display2ViewModel(); // cannot convert source type error          
    }
}

Display1View.xaml

<UserControl x:Class="TestCaliMiContentControl.Display1View"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         d:DesignHeight="300"
         d:DesignWidth="300"
         mc:Ignorable="d">
    <Grid>
        <TextBlock HorizontalAlignment="Center" FontSize="72" 
                   Text="View 1"/>
     </Grid>
</UserControl>

Display1ViewModel.cs

using System;
using System.Windows.Controls;
using Caliburn.Micro;

namespace TestCaliMiContentControl
{
    public class Display1ViewModel : PropertyChangedBase {}
}

首先,我建议您阅读 Caliburn.Micro 文档,特别是关于屏幕、导体和组合的部分:http://caliburnmicro.com/documentation/composition

也就是说,我们可以修改您的代码以使其正常工作。

1) 由于您的 MainViewModel 应该进行其他项目,因此它应该来自 Conductor<T>。在这种情况下,我们将让它进行 Caliburn Screen class.

public class MainViewModel : Conductor<Screen>

2) 在 MVVM 中,你的视图模型应该对你的视图一无所知。您不应看到 UI class 等 ContentControl。我们可以将您的 属性 更改为 Screen 类型,但实际上我们根本不需要 属性,因为我们使用的是导体。因此,删除 MainGridContent 属性 和支持字段。

3) 在您的 Display1Display2 方法中,调用 Caliburn 的指挥方法 ActivateItem 以显示适当的项目。

public void Display1()
{
    ActivateItem(new Display1ViewModel());
}

4) 在您的 MainView.xaml 中,您需要将 ContentControl 绑定到指挥的活动项目 属性,按照惯例,ActiveItem.

<ContentControl x:Name="ActiveItem" Grid.Column="1" />

5) 最后,由于您的导体正在传导 Screens,您需要将它们制作成屏幕。屏幕很有用,因为它们具有生命周期并让您知道它们何时 activated/deactivated。对 Display1 和 Display2 执行此操作。

public class Display1ViewModel : Screen {}

这会让你起床 运行。