获取在 Bootstrapper 的 OnStartup 中创建的 View Model 实例

Get an instance of View Model created in OnStartup in the Bootstrapper

我对 WPF 和 Caliburn 还是很陌生,但是,鉴于我的引导程序中有以下内容 class:

    protected override void OnStartup(object sender, StartupEventArgs e)
    {
        DisplayRootViewFor<MainWindowViewModel>();
    }

据我了解(或不了解),DisplayRootViewFor 创建 View 和 ViewModel classes 的实例,绑定它们并显示它们。所以我想要的是能够获得 ViewModel class 的那个实例。可能是我一般并不真正理解 MVVM 原则,但本质上,在我看来,我希望能够说一些简单的事情,比如:

    MainWindowViewModel vm = ?;
    vm.Property = "Hi this is a test";

那么 '?' 中会出现什么?或者这只是普遍不受欢迎?

编辑: 正如下面带有评论的回答中提到的,我希望与 Avalon Dock 一起工作,这在从 MVVM 部分访问方面是出了名的糟糕。实际上,我只是在寻找一种方法来找到调用 OnStartup 时创建的 ViewModel 的正确实例。这可能吗?

Caliburn Micro 的工作方式与大多数 MVVM 框架有点不同,因为它是模型优先的,即模型的名称(例如 MainWindowViewModel)决定创建什么视图(MainWindowView在本例中),Caliburn Micro 负责为这对创建和绑定接线。它使用许多标准(但可覆盖)约定来执行此操作。

视图模型 - 视图对背后的想法是,视图绑定并显示视图模型的内容和状态,并且当用户操作视图中的元素时,它会触发视图模型中的命令(例如按下按钮)。视图模型负责对这些命令做出反应,并相应地更新它的状态或内容。完成后,视图将反映新的状态或内容。

一般来说,如果您习惯于其他 MVVM 框架,这可能会造成混淆,Caliburn Micro 需要 0 行的 "code behind" 视图 class,因为所有绑定通常只能在 XAML 中完成。

用一个非常基本的屏幕示例进行说明,该屏幕允许从可用称呼列表中为用户选择称呼,显示所选用户称呼的预览,并允许保存它。

public class UserSalutationViewModel : Screen
{
    private readonly string _userName;
    private readonly IDataService _dataService;
    private string _selectedSalutation;

    public UserSalutationViewModel(string userName, IDataService dataService)
    {   
        _userName = userName;
        _dataService = dataService;
        Salutions = new BindableCollection<string>(_dataService.GetAvailableSalutations());
        _selectedSalutation = _dataService.GetUserSalutation(_userName);
    }

    // List with selectable salutations. Bound in the View to a ListBox element.
    public BindableCollection<string> Salutions { get; private set;}

    // Caliburn Micro will automatically bind this to the selected item in the ListBox.
    public string SelectedSalutation 
    {
        get { return _selectedSalutation; }
        set
        {
            _selectedSaluation = value;
            NotifyOfPropertyChange(() => SelectedSalutation);
            // Notify the view to refresh with the new user salutation value
            NotifyOfPropertyChange(() => UserSaluation);
        }
    }

    // This returns a model constructed value. Bound to a Label element in the View
    public string UserSalutation
    {
        get { return _selectedSaluation + " " + _userName; }
    }

    // Saves the selected salutation. Bound to a Button in the View
    public void Save()
    {
        _dataService.SaveUserSalutation(_userName, _selectedSalutation);
    }
}

那么 UserSalutationView XAML 也可以非常简单,只布置视图中的元素。

<UserControl x:Class="MyProject.UserSalutationView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:cal="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">

    <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0" x:Name="UserSalutation"/>  
        <ListBox Grid.Row="1" x:Name="Salutions"/>
        <Button Grid.Row="2" x:Name="Save" Content="Save user salutation"/>
    </Grid>

</UserControl>

XAML 中的 x:Name 部分用于 Caliburn 的 View 与 ViewModel 的连线。

要从视图中的隐藏代码直接访问 Caliburn 微视图模型,您可以访问其 DataContext 属性 并将其转换为视图模型类型。像这样(在 UserSalutationView.xaml.cs 中):

// Get my UserSalutationViewModel
var viewModelInstance = DataContext as UserSalutationViewModel;