Search code examples
wpfwpf-style

How do I create a dynamic context menu for ListBoxItems?


I have a style that doesn't seem to be working. In spite of Snoop telling me the DataContext for the ListBoxItem is correct, nothing shows up. If it was a problem with the binding for Commands I would expect to see an empty context menu appear.

The style:

<ContextMenu x:Key="CommandsContextMenu" ItemsSource="{Binding Commands}">
    <Style TargetType="MenuItem">
        <Setter Property="Header" Value="{Binding Name}"/>
    </Style>
</ContextMenu>

<Style TargetType="ListBoxItem">
    <Setter Property="ContextMenu" Value="{StaticResource CommandsContextMenu}" />
    <Style.Triggers>
        <DataTrigger Value="True">
            <DataTrigger.Binding>
                <Binding Path="DataContext.HasCommands" />
            </DataTrigger.Binding>
        </DataTrigger>
    </Style.Triggers>
</Style>

The snoop DataContext:

SnoopDataContext

The snoop properties showing the ContextMenu property isn't even set.

SnoopProperties

The idea here, was that without knowing any of the types, I could have a listbox item style where if the thing it was bound to has a property called HasCommands, and it was set to true, then it would set a context menu on that listbox item, bound to the Commands property.

I'm not getting any binding errors or warnings from PresentationTraceSources.DataBindingSource

Why doesn't the context menu get set?


Solution

  • So it turns out, that the problem was using something that inherited from ListBox

    for reference here's my defined class:

    // adapted from http://stackoverflow.com/questions/3350187/wpf-c-rearrange-items-in-listbox-via-drag-and-drop
    // which was probably adapted from http://wpftutorial.net/DragAndDrop.html
    type DragDropListBox() as self =
        inherit ListBox()
    

    which from there only hooks the following

    • self.PreviewMouseLeftButtonUp
    • self.PreviewMouseMove
    • override x.OnItemsSourceChanged

    and in the intialization it overwrites the ItemContainerStyle as follows:

    So it turns out, that the problem was using something that inherited from ListBox

    for reference here's the top of my class:

    // adapted from http://stackoverflow.com/questions/3350187/wpf-c-rearrange-items-in-listbox-via-drag-and-drop
    // which was probably adapted from http://wpftutorial.net/DragAndDrop.html
    type DragDropListBox() as self =
        inherit ListBox()
    

    which from there only hooks the following

    • self.PreviewMouseLeftButtonUp
    • self.PreviewMouseMove
    • override x.OnItemsSourceChanged

    and in the intialization it overwrites the ItemContainerStyle as follows:

    do
        self.PreviewMouseLeftButtonUp.Add listBoxPreviewMouseLeftButtonUp
        //self.PreviewMouseLeftButtonDown.Add listBoxPreviewMouseMove //.AddHandler (MouseButtonEventHandler previewMouseMove)
        self.PreviewMouseMove.Add listBoxPreviewMouseMove
        let style =
            let s = Style(typeof<ListBoxItem>)
            s.Setters.Add (Setter(ListBoxItem.AllowDropProperty, true))
            s.Setters.Add (EventSetter(ListBoxItem.PreviewMouseLeftButtonDownEvent, MouseButtonEventHandler listBoxPreviewMouseLeftButtonDown))
            s.Setters.Add (EventSetter(ListBoxItem.DropEvent, DragEventHandler listBoxItemDrop))
    
            s
        self.ItemContainerStyle <- style
    

    now I've got to figure out if you can add two styles together.