You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Caliburn.Micro时MenuItem无法传递Item至方法的问题

Caliburn.Micro上下文菜单传递分组参数为null的解决方法

我使用Caliburn.Micro实现MVVM模式,在DataGrid的上下文菜单中设置了一个包含分组列表的MenuItem,需求是点击子菜单时将选中的分组传递给OnGroupSelected(Group SelectedGroup)方法。目前上下文菜单能正常显示分组名称,方法也能触发,但传入的SelectedGroup参数始终为null。

原始XAML代码如下:

<DataGrid
    ItemsSource="{Binding Items}"
    SelectedItem="{Binding SelectedItem}"
    SelectionMode="Single">
    <DataGrid.ContextMenu>
        <ContextMenu MinWidth="200">
            <MenuItem
                cal:Message.Attach="[Click] = [Action OnGroupSelected($data)]"
                Header="Move Item to Group"
                ItemsSource="{Binding Groups}">
                <MenuItem.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Name}" />
                    </DataTemplate>
                </MenuItem.ItemTemplate>
            </MenuItem>
        </ContextMenu>
    </DataGrid.ContextMenu>
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding Name}" Header="Name" />
        <DataGridTextColumn Binding="{Binding Description}" Header="Description" />
    </DataGrid.Columns>
</DataGrid>

我尝试过给MenuItem添加ItemContainerStyle绑定消息,但依旧无效:

<MenuItem
    Header="Move Item to Group"
    ItemsSource="{Binding Groups}">
    <MenuItem.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Name}" />
        </DataTemplate>
    </MenuItem.ItemTemplate>
    <MenuItem.ItemContainerStyle>
        <Style TargetType="MenuItem">
            <Setter Property="cal:Message.Attach" Value="[Click] = [Action OnGroupSelected($data)]" />
        </Style>
    </MenuItem.ItemContainerStyle>
</MenuItem>

解决方法

问题核心在于上下文菜单中子MenuItem的DataContext绑定未正确指向分组项,且$data的作用范围错误。正确的写法需要确保每个子MenuItem的DataContext对应分组列表中的项,再通过$data传递参数。

方案1:简化写法(无需ItemTemplate)

<DataGrid
    ItemsSource="{Binding Items}"
    SelectedItem="{Binding SelectedItem}"
    SelectionMode="Single">
    <DataGrid.ContextMenu>
        <ContextMenu MinWidth="200">
            <MenuItem Header="Move Item to Group" ItemsSource="{Binding Groups}">
                <MenuItem.ItemContainerStyle>
                    <Style TargetType="MenuItem">
                        <!-- 将子MenuItem的DataContext绑定为当前分组项 -->
                        <Setter Property="DataContext" Value="{Binding}" />
                        <!-- 通过$data获取当前分组对象并传递给方法 -->
                        <Setter Property="cal:Message.Attach" Value="[Click] = [Action OnGroupSelected($data)]" />
                        <!-- 直接绑定Header显示分组名称 -->
                        <Setter Property="Header" Value="{Binding Name}" />
                    </Style>
                </MenuItem.ItemContainerStyle>
            </MenuItem>
        </ContextMenu>
    </DataGrid.ContextMenu>
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding Name}" Header="Name" />
        <DataGridTextColumn Binding="{Binding Description}" Header="Description" />
    </DataGrid.Columns>
</DataGrid>

方案2:保留ItemTemplate的写法

如果需要自定义子菜单的显示样式,保留ItemTemplate,只需确保DataContext正确绑定:

<DataGrid
    ItemsSource="{Binding Items}"
    SelectedItem="{Binding SelectedItem}"
    SelectionMode="Single">
    <DataGrid.ContextMenu>
        <ContextMenu MinWidth="200">
            <MenuItem Header="Move Item to Group" ItemsSource="{Binding Groups}">
                <MenuItem.ItemContainerStyle>
                    <Style TargetType="MenuItem">
                        <Setter Property="DataContext" Value="{Binding}" />
                        <Setter Property="cal:Message.Attach" Value="[Click] = [Action OnGroupSelected($data)]" />
                    </Style>
                </MenuItem.ItemContainerStyle>
                <MenuItem.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Name}" />
                    </DataTemplate>
                </MenuItem.ItemTemplate>
            </MenuItem>
        </ContextMenu>
    </DataGrid.ContextMenu>
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding Name}" Header="Name" />
        <DataGridTextColumn Binding="{Binding Description}" Header="Description" />
    </DataGrid.Columns>
</DataGrid>

原理说明

  • 原始写法中,cal:Message.Attach绑定在父MenuItem上,点击子菜单时$data指向的是父菜单的DataContext(即ViewModel),而非子项的分组对象。
  • 通过ItemContainerStyle给每个子MenuItem设置DataContext="{Binding}",让子菜单的上下文对应分组列表中的每一项,此时$data就能正确获取到Group实例。
  • 也可以直接在Action中使用{Binding}代替$data,即[Action OnGroupSelected({Binding})],效果完全一致。

内容的提问来源于stack exchange,提问作者Chi Hieu Phan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 07:03:18