ContextMenu for DraggableListBoxItem

2 posts, 0 answers
  1. Ken
    Ken avatar
    9 posts
    Member since:
    Apr 2018

    Posted 04 May Link to this post

    UI for WPF 2019.1.220.45, Windows 10 Pro 64, Visual Studio Community 2019 v16.0.3

    I'm trying to attach a context menu to a draggable listbox item, and after a great deal of effort, I've finally gotten it to the point where I can right click anywhere on the item (except for when the cursor is over a control with its own context menu, which is desired behavior).  So, this is functioning exactly as I want it to from a UI standpoint.  The problem is that the moment I add a Click property to the menu item in the xaml, the app throws an exception during the construction of the listbox.

    Here's the xaml

    <UserControl x:Class="MIDIMan.ZWMIDIInPortList"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                 xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
                 xmlns:local="clr-namespace:MIDIMan"
                 xmlns:viewmodel="clr-namespace:MIDIManViewModel;assembly=MIDIManViewModel"
                 xmlns:telerikDragDrop="clr-namespace:Telerik.Windows.Controls.DragDrop;assembly=Telerik.Windows.Controls"
                 mc:Ignorable="d"
                 d:DesignHeight="450" d:DesignWidth="800" BorderBrush="Black" BorderThickness="1">
        <UserControl.Resources>
            <viewmodel:InPortsViewModel x:Key="InPortsViewModel"/>
            <DataTemplate x:Key="InPortListTemplate">
                <Grid HorizontalAlignment="Left">
                    <Grid.RowDefinitions>
                        <RowDefinition/>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <CheckBox IsChecked="{Binding IsActive}" />
                    <TextBox Grid.Column="1" Text="{Binding PortName}" Width="Auto" BorderBrush="White" />
                </Grid>
            </DataTemplate>
            <Style x:Key="DraggableListBoxItem" TargetType="telerik:RadListBoxItem">
                <Setter Property="telerik:DragDropManager.AllowCapturedDrag" Value="True" />
                <Setter Property="ContextMenu">
                    <Setter.Value>
                        <ContextMenu>
                            <MenuItem Header="Restore port name" Click="MenuItem_Click"/>
                        </ContextMenu>
                    </Setter.Value>
                </Setter>
            </Style>
        </UserControl.Resources>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="30"/>
                <ColumnDefinition Width="65"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Text="Input Ports" HorizontalAlignment="Center"/>
            <TextBlock Grid.Row="1" Grid.Column="0" Text="Active" HorizontalAlignment="Center"/>
            <TextBlock Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" Text="Name" HorizontalAlignment="Center"/>
            <telerik:RadListBox Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3"
                                ItemsSource="{Binding MIDIInPorts, Source={StaticResource InPortsViewModel}}"
                                ItemTemplate="{StaticResource InPortListTemplate}"
                                ItemContainerStyle="{StaticResource DraggableListBoxItem}"
                                HorizontalAlignment="Stretch"
                                Height="Auto">
            <telerik:RadListBox.DragDropBehavior>
                    <telerik:ListBoxDragDropBehavior AllowReorder="True" />
                </telerik:RadListBox.DragDropBehavior>
                <telerik:RadListBox.DragVisualProvider>
                    <!--<telerik:ScreenshotDragVisualProvider />-->
                    <telerik:ListBoxDragVisualProvider/>
                </telerik:RadListBox.DragVisualProvider>
            </telerik:RadListBox>
            <StackPanel Orientation="Horizontal" Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="3" HorizontalAlignment="Center">
                <TextBlock Text="{Binding MIDIInPortCount, Source={StaticResource InPortsViewModel}}" Margin="0,0,5,0"/>
                <TextBlock Text="Ports" />
            </StackPanel>
        </Grid>
    </UserControl>

     

    I had been trying to put the ContextMenu in the ListBoxItem template, but was having no luck, when I ran across a forum post somewere that suggested putting it in its style instead, and that's what we have here.  You'll find it right about in the middle of the code - just a single MenuItem, "Restore port name".  If I remove the MenuItem altogether, the app runs fine and when I right click on the ListBoxItem, an empty context menu pops up.  If I add the MenuItem with no Click property, the context menu pops up and shows the menu item.  Add the Click property definition and, boom!  Exception thrown.

    I'm attaching some pictures that include what the list box looks like and the exception warning and details.

    I wanted to use the RadContextMenu, but the app wouldn't build because it only allows ContexMenu at that point.  (Different exception)

    Any suggestions as to what I might do to get it working?

    Thanks,

    Ken

  2. Dilyan Traykov
    Admin
    Dilyan Traykov avatar
    949 posts

    Posted 08 May Link to this post

    Hello Ken,

    Thank you for the provided images and code snippet.

    I can confirm that I was able to replicate the exception at my end even with the standard MS ListBox control, which leads me to believe that this issue stems from the WPF Framework. It seems to be caused by the implicit style but if you want to further investigate the specific reason for this exception, I can suggest forwarding this to the MSDN or StackOverflow forums to get an expert opinion. You can provide this isolated code snippet which is enough to throw the exception:

    <Grid>
        <Grid.Resources>
            <Style TargetType="ListBoxItem">
                <Setter Property="ContextMenu">
                    <Setter.Value>
                        <ContextMenu>
                            <MenuItem Click="MenuItem_Click" />
                        </ContextMenu>
                    </Setter.Value>
                </Setter>
            </Style>
        </Grid.Resources>
        <ListBox>
            <ListBoxItem />
        </ListBox>
    </Grid>

    Luckily, I was able to workaround this exception by attaching the handler in the following manner:

    <Style TargetType="telerik:RadListBoxItem">
        <Setter Property="telerik:RadContextMenu.ContextMenu">
            <Setter.Value>
                <telerik:RadContextMenu>
                    <telerik:RadContextMenu.ItemContainerStyle>
                        <Style TargetType="telerik:RadMenuItem">
                            <EventSetter Event="Click" Handler="MenuItem_Click" />
                        </Style>
                    </telerik:RadContextMenu.ItemContainerStyle>
                    <telerik:RadMenuItem Header="Click" />
                </telerik:RadContextMenu>
            </Setter.Value>
        </Setter>
    </Style>

    You can then get ahold of the clicked menu item's parent RadListBoxItem by using the GetClickedElement method of the RadContextMenu as explained here.

    private void MenuItem_Click(object sender, RoutedEventArgs e)
    {
        var menuItem = e.Source as RadMenuItem;
        var menu = menuItem.Parent as RadContextMenu;
        var item = menu.GetClickedElement<RadListBoxItem>();
    }

    For your convenience, I've prepared a small sample project demonstrating this approach.

    Please have a look and let me know if something similar would work at your end. I will be awaiting your reply.

    Regards,
    Dilyan Traykov
    Progress Telerik
    Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
Back to Top