2016-02-02 59 views
0

我有一个MainView,其DataContext是我的MainViewModel。Caliburn.Micro:调用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> 

我希望卡利很聪明,解决ProjectVM.ShowNewProjectDialog,但事实并非如此。有没有什么好的方法来做到这一点,而不必手动设置菜单的DataContext?

回答

1

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

正如你可以在名为All About Actions的卡利微文档部分阅读:

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附加属性,其中来自所有邮件(即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; 
     } 
    } 
}; 

我希望它可以帮助你。