Search code examples
c#wpflistbox

how do I get the text that a user right clicks on in a listbox when the listbox is populated by a List<> and selectionMode is Multi?


I have a project that follows the MVVM format. In this project there is a listbox. The listbox items are populated from a list of custom class objects (DataMessages), each displayed listbox item is made up of 2 textboxes, one showing the date and time, the other a text string.

The listbox allows the user to select one or more messages for cutting and pasting, etc.

When the user right clicks on the text string a context menu shows up, and the user can select "Decode message". When the user selects "Decode Message" a new window pops up that gives the details of the message.

I am having trouble getting the text that is clicked on. The item does not need to be selected for this to work. Since the text is already bound to the list items I don't know how to get the text.

My XAML code correctly displays the data and context menu.

<ListBox Grid.Column="0" Grid.Row="1" SelectionMode="Extended" Name="DistinctMessages" Margin="10,0,10,10" ItemsSource="{Binding Path=DATADisplayMessages}" SelectedItem="{Binding Path=SelectedUniqueMessages, Mode=TwoWay}">
                <ListBox.Resources>
                    <BooleanToVisibilityConverter x:Key="boolToVisibility"/>
                </ListBox.Resources>
                <ListBox.InputBindings>
                    <KeyBinding Key="C" Modifiers="Ctrl" Command="{Binding CopySelectedMessageToClipBoard}" CommandParameter="{Binding ElementName=DistinctMessages, Path=SelectedItems}"/>
                </ListBox.InputBindings>
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Text="{Binding RecivedTime, StringFormat=dd-MM-yyyy HH:mm:ss.fff}" Margin="0,0,10,0" Visibility="{Binding ElementName=CheckTimeStampFiltered, Path=IsChecked, Converter={StaticResource boolToVisibility}}"/>
                            <TextBlock Text="{Binding Message}">
                                <TextBlock.ContextMenu>
                                    <ContextMenu DataContext="{Binding DataContext, Source={local:RootObject}}">
                                        <MenuItem Header="Decode Message" Command="{Binding OpenMessageDecodeWindow}"/>
                                    </ContextMenu>
                                </TextBlock.ContextMenu>
                            </TextBlock>
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>

When clicking on "Decode Message" in the context menu the function is called correctly, and the window opens.

private void ExecuteOpenMessageDecodeWindow()
    {
        //SelectedUniqueMessages
        MessageDecodeWindow mdWin = new MessageDecodeWindow()
        {
            DataContext = new MessageDecodeWindowViewModel()
            {
                DATAMessage = "What do I put here?" 
            }
        };
        mdWin.ShowDialog();
    }

What do I need to add to get the text string that is right clicked on to set "DATAMessage" equal to it?


Solution

  • You could use the CommandParameter property to pass the value to the command:

    <TextBlock Text="{Binding Message}">
        <TextBlock.ContextMenu>
            <ContextMenu>
                <MenuItem Header="Decode Message"
                          Command="{Binding DataContext.OpenMessageDecodeWindow, Source={local:RootObject}}"
                          CommandParameter="{Binding PlacementTarget.DataContext.Message, RelativeSource={RelativeSource AncestorType=ContextMenu}}"/>
            </ContextMenu>
        </TextBlock.ContextMenu>
    </TextBlock>
    

    Depending in your ICommand implementation, you may then need to cast the parameter of the Execute(object parameter) method to a string in your view model.