使用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
相关产品推荐
相关产品推荐

