【问题标题】:"No target found for method" thrown by Caliburn Message.Attach()Caliburn Message.Attach() 抛出“找不到方法的目标”
【发布时间】:2012-11-15 06:13:05
【问题描述】:

我有一个列表框,我为其设置了 ItemContainer 样式以包含上下文菜单。这是相同的 xaml。

<ListBox.ItemContainerStyle>
    <Style TargetType="{x:Type ListBoxItem}">
    ...
        <Setter Property="ContextMenu">
            <Setter.Value>
                <ContextMenu>
                    <MenuItem Header="Remove Group" cal:Message.Attach="DeleteGroup"/>
                </ContextMenu>
            </Setter.Value>
        </Setter>
    </Style>

我已经在 ViewModel 中编写了目标方法,如下所示。

public void DeleteGroup() { //ToDo
    ...
}

ViewModel 设置为包含 ListBox 的 UserControl 的 DataContext。

上面的代码导致“找不到方法的目标”。我不确定为什么这不起作用。我也尝试了以下变体

<MenuItem Header="Remove Group" cal:Message.Attach="DeleteGroup"
          cal:Action.Target="{Binding ElementName=UCRelayDispositionView, Path=DataContext}">

其中 UCRelayDispositionView 是 UserControl 的名称。

为什么上面的代码不起作用?

编辑:1 还尝试了以下

<MenuItem Header="Remove Group" cal:Message.Attach="DeleteGroup"
          cal:Action.TargetWithoutContext="{Binding ElementName=UCRelayDispositionView, Path=DataContext}">

还有这个

<MenuItem Header="Remove Group" cal:Message.Attach="DeleteGroup"
          cal:Action.TargetWithoutContext="{Binding ElementName=UCRelayDispositionView}">

编辑:2 我曾尝试在 ItemContainer 上按以下方式使用 Tag,但它也不起作用。

<ListBox.ItemContainerStyle>
    <Style TargetType="{x:Type ListBoxItem}">
        <Setter Property="Tag" Value="{Binding Path=DataContext, ElementName=UCRelayDispositionView}"/>
        <Setter Property="ContextMenu">
            <Setter.Value>
                <ContextMenu>
                    <MenuItem Header="Remove Group" 
                              cal:Message.Attach="DeleteGroup()" 
                              cal:Action.TargetWithoutContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}"/>                                    
                    </ContextMenu>
            </Setter.Value>
    </Style>
</ListBox.ItemContainerStyle>

编辑 3:绑定错误

System.Windows.Data Error: 40 : BindingExpression path error: 'PlacementTarget' property not found on 'object' ''MenuItem' (Name='')'. BindingExpression:Path=PlacementTarget.Tag; DataItem='MenuItem' (Name=''); target element is 'MenuItem' (Name=''); target property is 'TargetWithoutContext' (type 'Object')
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=UCRelayDispositionView'. BindingExpression:Path=DataContext; DataItem=null; target element is 'ContextMenu' (Name=''); target property is 'Tag' (type 'Object')

【问题讨论】:

    标签: c# wpf caliburn.micro wpf-4.0


    【解决方案1】:

    您的问题在于您试图将目标绑定到同一可视树中不存在的元素,例如您有一个ContextMenu,该项目所在的位置。

    要正确获取操作目标,您需要使用ContextMenus PlacementTarget 属性。

    查看有关 XAML 的 SO 的以下答案

    WPF Context Menus in Caliburn Micro

    所以下面的 XAML 应该可以工作:

    <MenuItem Header="Blah" cal:Message.Attach="SomeMethod()" cal:Action.TargetWithoutContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}">
    

    这应该在ContextMenu 上查找PlacementTarget,并将操作的目标设置为PlacementTarget.Tag 的值(应该是ListBoxItem)。

    如果您将ListBoxItem.Tag(正如您已经完成的那样)设置为父容器(ListBox)的DataContext,您应该没问题

    所以标签绑定应该是:

    <Setter Property="Tag" Value="{Binding Path=DataContext, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBox}}"/>
    

    例如整个事情应该是:

    <ListBox.ItemContainerStyle>
        <Style TargetType="{x:Type ListBoxItem}">
            <Setter Property="Tag" Value="{Binding Path=DataContext, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBox}}"/>
            <Setter Property="ContextMenu">
                <Setter.Value>
                    <ContextMenu cal:Action.TargetWithoutContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}">
                        <MenuItem Header="Remove Group" cal:Message.Attach="DeleteGroup()" />
                    </ContextMenu>
                </Setter.Value>
            </Setter>
        </Style>
    </ListBox.ItemContainerStyle>
    

    【讨论】:

    • 您的代码不起作用。仍然给出同样的错误。就使用 Tag 而言,我应该把它放在哪里?我在 ItemContainerStyle 上有这个上下文菜单!
    • 如果您查看我发布的 SO 链接,这里有一个放置位置的示例。基本上,您必须使用ContextMenu.PlacementTarget 属性来获取生成上下文菜单的项目并绑定到它的DataContext,尽管它可能需要您将父容器的DataContext 破解到Tag 属性中。这对我有用(可能值得在视图中创建一个事件,这样您就可以在单击菜单项时进入代码隐藏和调试。这样您就可以探索对象图并发现正确的绑定路径)
    • 我已编辑标记为 EDIT 2 的问题。我不确定我们是否可以像这样使用 Style 设置 Tag,但仍然存在相同的错误。
    • 这个答案令人困惑。如果代码不正确,请将其删除,并在答案中仅包含正确的代码。如果人们想查看您进行了哪些编辑,他们可以查看修订历史记录。用下面的“编辑”部分保留不正确的代码对任何人都没有帮助。
    • @MgSam 感谢您的建议(大约一年前!)-我已经更新了答案:)
    【解决方案2】:

    添加到 Charleh 的回答中,如果您要使用与控件相同的数据上下文,那么您可以绑定 DataContext 而不是 Tag。也让它更干净一些。

    <ListBox.ItemContainerStyle>
        <Style TargetType="{x:Type ListBoxItem}">
            <Setter Property="ContextMenu">
                <Setter.Value>
                    <ContextMenu cal:Action.TargetWithoutContext="{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}" >
                        <MenuItem Header="Remove Group"
                                  cal:Message.Attach="DeleteGroup()" />
                    </ContextMenu>
                </Setter.Value>
            </Setter>
        </Style>
    </ListBox.ItemContainerStyle>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-02
      • 1970-01-01
      • 2014-02-25
      • 2015-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多