3
votes

I am trying to implement what I used to take for granted in Winforms applications. I am a Silverlight noob, so hopefully all this is elementary.

I have a listbox in a Silverlight 4 app. I'd like to do the following:

  1. Right-click on the listbox
  2. Have the item under the location where I click highlight itself
  3. I'd like a context menu to popup (with my own items in the context menu)

From my research so far, it appears that there is no ContextMenu construct in Silverlight, instead we have to build up a Grid/Canvas structure and attach it to a Popup object, which is what is then popped up.

My questions are as follows:

  1. To accomplish #2, I need some kind of hit test on the listbox. I can't figure out how to do that and my google-fu isn't helping.
  2. Once I do identify the index under the mouse, how do I actually select the item?
  3. Is there a reusable Context menu component somewhere that I can use? Extra credit if the component allows arbitrary sub-menus.
2

2 Answers

3
votes

I've been looking around for the same thing. I checked the Silverlight Control Toolkit at CodePlex and went through the samples (it's a very handy resource) and here's what I found to be the solution to what you asked:

  1. Create an ItemTemplate for your ListBox

  2. in the part that you want to be "right-clickable" of your ItemTemplate set the attached property ContextMenuService.ContextMenu that exists within the System.Windows.Controls.Input.Toolkit namespace

  3. add MenuItem controls to your ContextMenu and set the Click property to the corresponding click event handler

  4. in the event handler, get the DataContext from the sender (you can use that to find the corresponding element in the ListBox)

  5. to make that element Selected, just set the SelectedItem property in the list box to it

  6. Add any custom logic to the event handler

There's an example in the samples page, just go to "Input->ContextMenu" from the navigation pane.

If you want something concise, Here's a simplified example:

<ListBox ItemsSource="{StaticResource People}"
             Name="myListBox">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Name}">
                    <controlsInputToolkit:ContextMenuService.ContextMenu>
                        <controlsInputToolkit:ContextMenu>
                            <controlsInputToolkit:MenuItem Header="Show in MessageBox"
                                                           Click="show_Click" />
                        </controlsInputToolkit:ContextMenu>
                    </controlsInputToolkit:ContextMenuService.ContextMenu>
                </TextBlock>
            </DataTemplate>
        </ListBox.ItemTemplate>
</ListBox>

with:

xmlns:controlsInputToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input.Toolkit"

for the code:

private void show_Click(object sender, RoutedEventArgs e)
    {
        var person = ((MenuItem)sender).DataContext as Person;
        if (null == person) return;
        MessageBox.Show("My Name is: " + person.Name);
        myListBox.SelectedItem = person;
    }

I hope this helps :)

1
votes

There's the MouseRightButtonDown event. If you bind that on the ListBox:

<ListBox Height="143" Name="listBox1" Width="218"
         MouseRightButtonDown="listBox1_MouseRightButtonDown" />

you'll get what you need. The code behind is:

private void listBox1_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
}

The MouseButtonEventArgs will give you the position via the GetPosition method.