Search code examples
c#wpfcontextmenumenuitemcaliburn.micro

MenuItem with Caliburn.Micro cannot pass the Item to the method


I have a following 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>

All I wanted to have a contextMenu appear when click on a DataGrid Item, it will show a List of available group that I want to move the Item to.

I can get the ContextMenu to show all the Group with their name and call the OnGroupSlected(Group SelectedGroup) but the SelectedGroup is null. How to pass the Item to OnGroupSlected correctly? I'm using Caliburn.Micro to handle the MVVM.

I have tried many approaches but none of them work:

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

Solution

  • I tried to solve your problem and ended up with this solution:

    1. In XAML use: cal:Message.Attach="[Click] = [Action OnGroupSelected($eventArgs)]"
    • you used $data which by default does not exists.

    And in your code you can access it like this:

    public void OnGroupSelected(RoutedEventArgs args)
    {
        if (args.OriginalSource is FrameworkElement fe)
        {
            if (fe.DataContext is Group group)
            {
                MessageBox.Show(group.Name);
            }
        }
    }
    
    1. Or you can use your $data in XAML, but in your code you need to specify (add it) it first: ...
    MessageBinder.SpecialValues.Add("$data", value =>
    {
        if (value.EventArgs is not RoutedEventArgs args)
            return null;
    
        if (args.OriginalSource is not FrameworkElement fe)
            return null;
    
        return fe.DataContext;
    });
    

    And in XAML use: cal:Message.Attach="[Click] = [Action OnGroupSelected($data)]"

    And in code:

    public void OnGroupSelected(Group SelectedGroup)
    {
        MessageBox.Show(SelectedGroup.Name);
    }
    

    Hopefully this will help you.