1

I'm beginner in MVVM and I've been trying to display MenuItems in a ContextMenu, but something seems to be wrong. I've already made a working Menu which has Itemssource bound to a collection in the viewmodel, but it doesn't work in case of the ContextMenu. Could you guys take a look and say if I'm missing something?

Here's the Menu, which works well:

<Menu DockPanel.Dock="right" ItemsSource="{Binding Path=modes}" Background="#FF303030" Foreground="White" Height="21">
    <Menu.Resources>
        <Style TargetType="{x:Type MenuItem}">
            <Setter Property="Background" Value="#FF303030"/>
            <Setter Property="Foreground" Value="White"/>
            <Setter Property="Height" Value="21" />
            <Setter Property="Visibility" Value="{Binding visibility}" />
            <Setter Property="Header" Value="{Binding header}" />
            <Setter Property="ItemsSource" Value="{Binding children}"/>
            <Setter Property="Command" Value="{Binding action}"/>
            <Setter Property="CommandParameter" Value="{Binding attachedData}"/>
        </Style>
    </Menu.Resources>
</Menu>

And here's the XAML of the ContextMenu, which, for some reason, doesn't display any MenuItems:

<Grid x:Name="btnMode" PreviewMouseDown="OnBtnModeMouseDown" Width="19" Height="19" Margin="0,0" DockPanel.Dock="Right">
    <Canvas>
        <Path Data="M0,0 L19,0 L19,19 L0,19" Margin="0,0" Fill="#FF303030"/>
        <Ellipse Height="12" Margin="4,3,0,0" Width="12" Fill="#FFFDFDFD"/>
        <Path Data="M1.5,1L18.5,1 L10,9.5" Margin="0,0,0,8.875" Fill="#FF303030"/>
    </Canvas>
    <Grid.ContextMenu>
        <ContextMenu ItemsSource="{Binding Path=modes}">
            <ContextMenu.ItemContainerStyle>
                <Style TargetType="MenuItem">
                    <Setter Property="Background" Value="#FF303030"/>
                    <Setter Property="Foreground" Value="White"/>
                    <Setter Property="Height" Value="21" />
                    <Setter Property="Visibility" Value="{Binding visibility}" />
                    <Setter Property="Header" Value="{Binding header}" />
                    <Setter Property="ItemsSource" Value="{Binding children}"/>
                    <Setter Property="Command" Value="{Binding action}"/>
                    <Setter Property="CommandParameter" Value="{Binding attachedData}"/>
                </Style>
            </ContextMenu.ItemContainerStyle>
        </ContextMenu>
    </Grid.ContextMenu>
</Grid>

I also have a ContextMenu that has hard-coded menu items:

<Grid x:Name="btnMenu" PreviewMouseDown="OnBtnMenuMouseDown" Width="19" Height="19" Margin="0,1" DockPanel.Dock="Right">
    <Canvas>
        <Path Data="M0,0 L19,0 L19,19 L0,19" Margin="0,0" Fill="#FF303030"/>
        <Path Data="M0,0L7,0 L3.5,7" Margin="6,7" Fill="White"/>
    </Canvas>
    <Grid.ContextMenu >
        <ContextMenu IsVisibleChanged="OnBtnMenuPopup">
            <MenuItem Name="menuFloatingWindow" Header="Floating window" Click="OnDockingMenu"></MenuItem>
            <MenuItem Name="menuDockedWindow" Header="Docked window" Click="OnDockingMenu"></MenuItem>
            <MenuItem Name="menuTabbedDocument" Header="Tabbed document" Click="OnDockingMenu"></MenuItem>
            <MenuItem Name="menuAutoHide" Header="Auto hide" Click="OnDockingMenu"></MenuItem>
            <MenuItem Name="menuClose" Header="Close" Click="OnDockingMenu"></MenuItem>
        </ContextMenu>
    </Grid.ContextMenu>
</Grid>

The collection of MenuItems is an ObservableCollection, defined as follows:

_menus = new ObservableCollection<MenuItem>()
{
    new MenuItem(
        "File",                // string header
        Visibility.Visible,    // Visibility visibility
        null,                  // ICommand action
        null,                  // object attachedData (CommandParameters)
        new ObservableCollection<MenuItem>()   // children
        {
            new MenuItem(
                "Exit",
                Visibility.Visible,
                MainWindow.exitCommand,
                null,
                null
            )
        }
    ),
    ...,  // more nested MenuItems here
};

Both the working Menu and the ContextMenu have the same ObservableCollection as an ItemSource.

Here's an image showing how the controls look in the application:

Menus

Did I mess something up in XAML?

P.S. I tried debugging the XAML at runtime using this: http://www.wpftutorial.net/DebugDataBinding.html but I couldn't see any helpful information when the breakpoint occured.

Community
  • 1
  • 1
mayqel
  • 28
  • 1
  • 7
  • It looks like you need to set the view to view-model data context. This will tell the view where to look for the binding. http://stackoverflow.com/questions/4590446/how-do-i-set-a-viewmodel-on-a-window-in-xaml-using-datacontext-property – MoonKnight Jul 17 '15 at 11:11
  • @Killercam Of course, I've set the DataContext. The Menu wouldn't be working otherwise. I have the Menu and the ContextMenu in the same user control, and they bind to the same DataContext. – mayqel Jul 17 '15 at 11:35
  • If you are getting an exception post the message here. Also, try and get the context menu working with the simplest possible collection first, then move on to child items... – MoonKnight Jul 17 '15 at 11:55
  • @Killercam I am not getting an exception; XAML and C# code compile without errors. I tested the ContextMenu on a collection that has nulled child collections, and I also removed the binding to subcollections (that is, I removed the ). In both cases, the MenuItems won't display. If you look closely, my code is really similar to the code here: http://stackoverflow.com/questions/18590730/wpf-submenu-for-context-menu I have no idea why it doesn't work... I already spent a lot of hours trying to solve this. – mayqel Jul 17 '15 at 12:09
  • Did you try to use RelativeSource ? – Ugur Jul 17 '15 at 12:18
  • ItemsSource="{Binding Path=modes, RelativeSource={RelativeSource AncestorType={x:Type Window}} } or ItemsSource="{Binding Path=modes, RelativeSource={RelativeSource AncestorType={x:Type UserControl}} } – Ugur Jul 17 '15 at 12:20
  • @Ugur My UserControl is neither a Window, nor a UserControl. In fact it's a Pane from DockingLibrary.DockablePane namespace. I don't know how to reference this custom type in relative source. Anyway, the DataContext works in the Menu. Why wouldn't it work for the ContextMenu? – mayqel Jul 17 '15 at 12:40
  • @MichałPłatek, could you please check the debug output, there should be some Binding exceptions related to this case. – Ugur Jul 17 '15 at 12:46
  • Here's the full XAML of the Pane, if you're interested: http://pastebin.com/vdEZDtqe At construction time, the ViewModel has an empty collection. It's updated afterwards, by a dedicated method. override public void updateModeMenu(ObservableCollection allowedTypes) { dockablePaneViewModel.modes = allowedTypes; MessageBox.Show(allowedTypes.Count.ToString() + " items on the list"); } This should update the View, but it seems not to. Although the XAML debugger stopped twice for two items in the collection – mayqel Jul 17 '15 at 12:49
  • @MichałPłatek, ItemsSource="{Binding Path=DataContext.modes, ElementName= } , please try with DataContext.modes. In this case, your element name x:Name="yourPaneName" – Ugur Jul 17 '15 at 12:53
  • @Ugur Changing the Binding to RelativeSource caused no change whatsoever. There are no Binding Exceptions in the Output, too. I also tried RelativeSource for the MenuItems, like this: {Binding RelativeSource={x:Static RelativeSource.Self}, Path=children}, but the result is still exactly the same. No errors, no menu Items. – mayqel Jul 17 '15 at 13:17
  • @MichałPłatek, really strange, I am really sorry that I could not help to you :( – Ugur Jul 17 '15 at 13:19
  • @Ugur I truly appreciate your effort. Thank you! :) – mayqel Jul 17 '15 at 13:36

0 Answers0