是否可以使用ViewModel第一种方法从View订阅ViewModel事件?

时间:2013-09-02 05:27:52

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

我使用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个实例,对吗?那么,如何避免这种情况呢?这是问题的一部分。

1 个答案:

答案 0 :(得分:0)

如果您正在执行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>

示例 - 使用指挥

VM:

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>

除了上述内容之外,我的建议是不要将viewmodel声明为资源,因为您在视图中创建了对该VM的依赖关系。您也分散了参考定位和处理的问题,并将其传播到您的视图中,这可能导致维护难题和意大利面条代码。

请记住,您希望将班级复杂性降至最低,以便您的班级应遵循单一责任原则 - 即他们应关注一个功能区域,并且不应对该单一范围之外的工作负责。这就是我们拥有IoC容器的原因,他们可以管理您的参考资料(作为他们唯一责任的组件!)

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

通过这种方式,您可以在VM中指定所需的依赖关系,但无法解析和控制这些依赖关系

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

  • 使用操作消息 - 您可以在视图中附加操作消息以处理事件,这将调用附加的viewmodel上的方法

e.g。

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

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

  • 使用事件聚合器 - 您通过实施IHandle<T>来订阅聚合器并侦听特定类型的消息,其中T是您感兴趣的消息类型

我将指出视图或VM在任何时候都不会相互引用 - 尽管可能,但除非确实有必要,否则应该避免使用它。视图模型应该幸福地不知道视图,对象之间没有耦合。 Caliburn Micro可以将VM粘贴到视图中,并且它可以很好地完成这项工作。

对象越分离,就越容易(不可避免)进行更改,重构和添加。

如果您正在努力使用CM,我建议您浏览CodePlex网站上的所有教程

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