【问题标题】:Get an instance of View Model created in OnStartup in the Bootstrapper获取在 Bootstrapper 的 OnStartup 中创建的 View Model 的实例
【发布时间】:2015-04-18 11:51:58
【问题描述】:

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

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

据我了解(或不了解),DisplayRootViewFor 创建 View 和 ViewModel 类的实例,绑定它们并显示它们。所以我想要的是能够获得 ViewModel 类的实例。可能是我总体上并没有真正理解 MVVM 原理,但本质上,在我看来,我想说一些简单的话:

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

那么'?'中会写什么?或者这只是一般情况下不受欢迎的?

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

【问题讨论】:

    标签: c# wpf mvvm caliburn.micro


    【解决方案1】:

    Caliburn Micro 的工作方式与大多数 MVVM 框架有点不同,因为它是模型优先的,即模型的名称(例如 MainWindowViewModel)决定了创建的视图(在这种情况下为 MainWindowView),并且Caliburn Micro 负责该对的创建和绑定布线。它使用许多标准(但可覆盖)约定来做到这一点。

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

    一般来说,如果您习惯于其他 MVVM 框架,这可能会让人感到困惑,Caliburn Micro 需要 0 行“隐藏代码”用于您的 View 类,因为所有绑定通常都可以在仅限 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。然而,像 Avalon Dock 这样的东西在提供 MVVM 支持方面出了名的糟糕,因此必须在视图背后的代码中将动态项添加到 Avalon Dock。如果我没有在启动时创建的 ViewModel 类的实例,如何从 View 订阅 ViewModel 中的事件?因此,原来的问题。感谢您的详细回答。
    • 如果您在问题中更具体地了解您想要实现的目标,而不是询问是否不赞成通过后面的代码操作视图模型(如它是,当通常有更好的方法可用时。我相信您提到的 Avalon Dock 问题的解决方案可以在这里找到:caliburnmicro.codeplex.com/discussions/430994 并查看github.com/tgjones/gemini
    • 我将把它标记为答案,即使它并不是我真正使用的,因为我认为这可能比我写的软糖更适合未来的开发者追求它工作。感谢您的帮助
    • 不客气,没有难过的感觉。如果你的问题表述得更准确一点,它就不会存在;-)
    【解决方案2】:

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

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

    【讨论】:

    • 我试过这个。我需要在视图构造函数中访问。我的 ViewModel 设置正确,但是在调试时 DataContext 为空。她知道何时在 Caliburn.Micro 中设置了数据上下文吗?获取这些数据的地方是什么,在渲染视图之前我需要它。
    猜你喜欢
    • 1970-01-01
    • 2012-11-24
    • 1970-01-01
    • 2011-09-09
    • 2022-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多