【问题标题】:Is it possible to subscribe to the ViewModel events from the View using ViewModel first approach?是否可以使用 ViewModel 第一种方法从 View 订阅 ViewModel 事件?
【发布时间】:2013-09-05 03:33:07
【问题描述】:

我使用 Caliburn.Micro。好吧,说实话,这就是我所面临的全部问题:

我在设计时设置了绑定。请看下面的代码:

<Window x:Class="Microtech.TPM.Views.DestinationChoiceView"       
    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"
    xmlns:vmns="clr-namespace:Microtech.TPM.ViewModels"
    mc:Ignorable="d"
    d:DataContext="{d:DesignInstance Type=vmns:DestinationChoiceViewModel, IsDesignTimeCreatable=True}"
    cal:Bind.AtDesignTime="True" Width="1280" Height="1024">
<Window.Resources>
    <vmns:DestinationChoiceViewModel x:Key="ViewModelKey" />
</Window.Resources>

我需要订阅 ViewModel 的事件。如果我在 Window.Resources 中定义了对 ViewModel 的引用并将其用于 xaml 中的进一步绑定,如何实现这一点?我完全不明白如何使用相同的引用。此外,我完全不明白这段代码已经拥有多少个 ViewModel 实例。据我了解,我至少会有 2 个实例,对吗?那么,如何避免这种情况呢?这是问题的一部分。

【问题讨论】:

    标签: wpf data-binding mvvm datacontext caliburn.micro


    【解决方案1】:

    如果您正在执行 ViewModel-First 绑定,您应该已经使用 Bootstrapper 类为您的应用程序层次结构创建根视图模型。

    在这种情况下,您要么需要绑定到包含位于根 VM 上的 ViewModel 的属性,要么需要将 VM 设为 ConductorActivate 在其中的一个或多个项目.

    示例 - 将其他虚拟机绑定为属性

    你的虚拟机:

    public class RootViewModel : PropertyChangedBase
    {
        private SomeOtherViewModel _someOtherView;
        public SomeOtherViewModel SomeOtherView
        {
            get { return _someOtherView; }
            set 
            {
                if(_someOtherView != value)
                {
                     _someOtherView = value;
                     NotifyOfPropertyChange(() => SomeOtherView);
                }
            }
        }
    }
    

    以及相关的视图:

    <Window x:Class="SomeProject.SomeView">
        <... some view related code - buttons etc ...>
        <!-- Render the other ViewModel using CMs conventions -->
        <ContentControl x:Name="SomeOtherView">
    </Window>
    

    示例 - 使用导体

    虚拟机:

    public class RootViewModel : Conductor<IScreen>
    {
         public RootViewModel(SomeViewModel someViewModel)
         {
             ActivateItem(someViewModel);
         }        
    }
    

    以及相关的视图:

    <Window x:Class="SomeProject.SomeView">
        <... some view related code - buttons etc ...>
        <!-- Render the other ViewModel using CMs conventions -->
        <ContentControl x:Name="ActiveItem">
    </Window>
    

    除了上述之外,我的建议是不要将视图模型声明为资源,因为您正在视图中创建对该 VM 的依赖项。您还分散了对引用定位和处理的关注,并将其传播到您的视图中,这可能会导致维护问题和意大利面条式代码。

    请记住,您希望将类的复杂性降至最低,因此您的类应遵循单一职责原则 - 即它们应该关注一个功能领域,而不应该负责该单一范围之外的工作。这就是我们拥有 IoC 容器的原因,它们用于管理您的引用(作为一个组件,这是他们的单一职责!)

    Caliburn Micro 附带的 IoC 容器 SimpleContainer 适用于大多数项目;添加一个流行的 IoC 容器(例如 Castle Windsor/Ninject 等)很容易,并且有很多教程可以让它运行

    通过这种方式,您可以在 VM 中指定所需的依赖项,但不知道这些依赖项的解析和控制

    为了在您的虚拟机之间发送事件和消息,CM 有两种机制:

    • 使用动作消息 - 将动作消息附加到视图以处理事件,这将调用附加视图模型上的方法

    例如

    <Window x:Class="SomeProject.SomeView">
        <Button cal:Message.Attach="[Event Click] = [Action ButtonClicked()]">click me</Button>
    </Window>`
    

    (这将在您的 ViewModel 上调用 ButtonClicked() 方法)

    • 使用事件聚合器 - 您订阅聚合器并通过实现 IHandle&lt;T&gt; 来监听特定类型的消息,其中 T 是您感兴趣的消息类型

    我要指出,视图或虚拟机在任何时候都不会相互引用——尽管有可能,除非真的有必要,否则应该避免。视图模型应该完全不知道视图,对象之间没有耦合。 Caliburn Micro 可以将 VM 粘合到视图上,它在这方面做得很好。

    您的对象越解耦,就越容易进行(不可避免的)更改、重构和添加。

    如果您在使用 CM 方面遇到困难,我建议您浏览 CodePlex 网站上的所有教程

    http://caliburnmicro.codeplex.com/wikipage?title=Basic%20Configuration%2c%20Actions%20and%20Conventions&referringTitle=Documentation

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-11
      • 2022-08-14
      • 1970-01-01
      • 2011-08-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多