【问题标题】:Caliburn.Micro: Call method of property on DataContextCaliburn.Micro:DataContext 上属性的调用方法
【发布时间】:2016-02-02 10:56:13
【问题描述】:

我有一个 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();
    }
}

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

目前我的 MainView 如下所示:

  <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,但事实并非如此。有什么好的方法可以做到这一点,而不必手动设置菜单的 DataContext?

【问题讨论】:

    标签: c# wpf mvvm caliburn.micro


    【解决方案1】:

    你是对的,Caliburn 并没有那么聪明地以你希望的方式解析 MethodName 属性。无论如何,它是一个强大的工具,可以根据您的需要轻松定制。

    您可以在名为 All About Actions 的 Caliburn 微文档部分阅读:

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

    这意味着 - 如果您需要 - 您可以手动设置将处理您的消息的“目标”。您可以使用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 附加属性,我们声明所有来自Menu 子级的消息(即ActionMessages)都将由ProjectViewModel 处理。 现在,如果您运行您的项目,您会发现它不起作用。原因是 Caliburn Micro 使用 VisualTreeHelper 来遍历 XAML 树。为了我们的目的,我们需要使用LogicalTreeHelper

    所以最后一步就是在BootstrapperConfigure方法中加入这段代码:

    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;
            }
        }
    };
    

    希望对你有帮助。

    【讨论】:

      猜你喜欢
      • 2015-12-03
      • 2016-09-04
      • 2012-01-27
      • 2012-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-05
      相关资源
      最近更新 更多