Caliburn.Micro:在 DataContext 上调用属性的方法

本文关键字:调用 属性 方法 DataContext Micro Caliburn | 更新日期: 2023-09-27 18:32:49

我有一个 MainView,它的 DataContext 就是我的 MainViewModel。

主视图模型:

class MainViewModel : PropertyChangedBase
{
    #region Properties
    /// <summary>
    /// The ProjectViewModel.
    /// </summary>
    public ProjectViewModel ProjectVM
    {
        get { return _projectVM; }
        private set
        {
            _projectVM = value;
            NotifyOfPropertyChange(() => ProjectVM);
        }
    }
    private ProjectViewModel _projectVM;
    #endregion
    /// <summary>
    /// Constructor.
    /// </summary>
    public MainViewModel()
    {
        ProjectVM = new ProjectViewModel();
    }
}

现在,我的主视图上有一个菜单。我想将 MenItems 的 Click 事件绑定到 ProjectVM 对象上的方法。当然,我知道我可以设置菜单项的DataContext,但我想知道是否有更简单的方法。

目前我的主视图看起来像这样:

  <Grid>
<Grid.RowDefinitions>
  <RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Menu Grid.Row="0">
  <MenuItem Header="File">
    <MenuItem Header="New Project...">
      <i:Interaction.Triggers>
        <i:EventTrigger EventName="Click">
          <cal:ActionMessage MethodName="ProjectVM.ShowNewProjectDialog"/>
        </i:EventTrigger>
      </i:Interaction.Triggers>
    </MenuItem>
    <MenuItem Header="Load Project..."/>
    <MenuItem Header="Close Project..."/>
  </MenuItem>
</Menu>

我曾希望Caliburn足够聪明,可以解决ProjectVM.ShowNewProjectDialog,但事实并非如此。有什么好方法可以做到这一点,而不必手动设置菜单的数据上下文?

Caliburn.Micro:在 DataContext 上调用属性的方法

你是

对的,Caliburn并不是那么聪明,可以按照你想要的方式解析MethodName属性。无论如何,它是一个功能强大的工具,可以根据您的需要轻松定制。

正如您可以在名为"所有关于操作"的Caliburn微文档部分中读到的那样:

当然,ActionMessage是Caliburn.Micro的特定部分。 标记。它表明当触发器发生时,我们应该发送一个 "说你好"的消息。那么,为什么我使用"发送消息"语言 而不是在描述此功能时"执行方法"? 这是有趣而强大的部分。操作消息气泡 通过可视化树搜索可以 处理它。

这意味着 - 如果需要 - 您可以手动设置将处理您的消息的"目标"。可以使用 Action.Target 附加属性执行此操作。当然,您不想为每个MenuItem设置它,因此您可以直接在Menu对象中设置:

<Menu cal:Action.Target="{Binding Path=ProjectVM, Mode=OneWay}">
    <MenuItem Header="File">
        <MenuItem Header="New Project..." cal:Message.Attach="ShowNewProjectDialog" />
        <MenuItem Header="Load Project..."/>
        <MenuItem Header="Close Project..."/>
    </MenuItem>
</Menu>

通过设置 Action.Target 附加属性,我们声明来自菜单子级的所有消息(即操作消息(将由ProjectViewModel处理。现在,如果您运行项目,您将看到它不起作用属性。原因是 Caliburn Micro 使用该VisualTreeHelper遍历 XAML 树。出于我们的目的,我们需要使用 LogicalTreeHelper .

所以最后一步是在 Bootstrapper Configure 方法中添加这段代码:

ActionMessage.SetMethodBinding = delegate(ActionExecutionContext context)
{
    FrameworkElement source = context.Source;
    for (DependencyObject dependencyObject = source; dependencyObject != null; dependencyObject = LogicalTreeHelper.GetParent(dependencyObject))
    {
        if (Caliburn.Micro.Action.HasTargetSet(dependencyObject))
        {
            object handler = Message.GetHandler(dependencyObject);
            if (handler == null)
            {
                context.View = dependencyObject;
                return;
            }
            MethodInfo methodInfo = ActionMessage.GetTargetMethod(context.Message, handler);
            if (methodInfo != null)
            {
                context.Method = methodInfo;
                context.Target = handler;
                context.View = dependencyObject;
                return;
            }
        }
    }
    if (source != null && source.DataContext != null)
    {
        object dataContext = source.DataContext;
        MethodInfo methodInfo2 = ActionMessage.GetTargetMethod(context.Message, dataContext);
        if (methodInfo2 != null)
        {
            context.Target = dataContext;
            context.Method = methodInfo2;
            context.View = source;
        }
    }
};

我希望它能帮助你。