David Veeneman
David Veeneman

Reputation: 19132

WPF ListBoxItem double-click?

The WPF ListBox doesn't have a DoubleClick event, at least not as far as I can tell. Is there a workaround for this issue that would let me double-click on an item to have an event handler do something with it? Thanks for your help.

Upvotes: 35

Views: 50502

Answers (9)

clementgamache
clementgamache

Reputation: 100

None of the current answers worked in my case since I am using SelectionMode="Multiple", so I just want to share with you the cleanest way I found to implement this feature.

First, I created a handler for a ListBoxItem included:

public void listBoxItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
    ListBoxItem clickedItem = ((ListBoxItem)sender);
            
    for (int i = 0; i < listBox.Items.Count; i++)
    {
        if (listBoxECIRatioSizeAutoSelect.Items[i] == clickedItem)
        {
            doStuff(i);
            break;
        }
    }
}

Then, whenever a ListBoxItem is added to the ListBox, the Handler is added to the ListBoxItem:

private void addItemToListBox(string strItem)
{
    ListBoxItem newItem = new ListBoxItem();
    newItem.Content = strItem;
    newItem.MouseDoubleClick += listBoxItem_MouseDoubleClick;
    listBox.Items.Add(newItem);
}

Upvotes: 0

Wouter
Wouter

Reputation: 2262

According to an MSDN article you can add a handler to every item in the listbox as follows:

<ListBox>
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <EventSetter Event="MouseDoubleClick" Handler="ListBoxItem_MouseDoubleClick"/>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

In the code behind you would then handle the double click. You could can then get access to the DataContext via sender.DataContext in the handler. Since double clicking selects an item you could also use the SelectedItem property or similar properties on the ListBox.

Personally I'd prefer a Behavior solution that allows redirection to a command, but I'm not sure how to implement that.

Upvotes: 5

Grunwaldt
Grunwaldt

Reputation: 51

On the double-click event use:

if (e.OriginalSource.GetType().ToString() == "System.Windows.Controls.TextBlock")
     DoubleClickDoneOnItem(); 

Upvotes: 0

Travis Banger
Travis Banger

Reputation: 81

The ListBox has a double click event now.

Upvotes: 1

marapet
marapet

Reputation: 56566

It is possible to bind commands with parameters to ListBoxItems without using code-behind or attached behaviors, simply by using InputBindings with a MouseBinding, as shown before in this answer.

Example ListBox with MouseBinding for LeftDoubleClick:

<ListBox ItemsSource="{Binding MyDataSource}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding MySourceItemName}">
                <TextBlock.InputBindings>
                    <MouseBinding MouseAction="LeftDoubleClick"
                                  Command="{Binding DataContext.MyCommand, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}"
                                  CommandParameter="{Binding MySourceItemId}" />
                </TextBlock.InputBindings>
            </TextBlock>
        </DataTemplate> 
    </ListBox.ItemTemplate>
</ListBox>

If the command is defined in the same DataContext as the ItemsSource of the ListBox, it can be bound by using the RelativeSource binding as included in the example.

Upvotes: 46

user3313608
user3313608

Reputation: 251

I have used the above answer from David (which starts with 'It turns out there is a MouseDoubleClick event for the ListBox.') to generate a solution that is based on his approach but is implemented with an attached behavior.

I am not saying you shall not have any code behind because I know there are situations where it should not be avoided for any price. But, this is yet another example of how you can convert an event based solution into an MVVM compliant solution that works via Event to command binding conversion.

This my attached behavior code:

using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Input;

/// <summary>
/// Class implements a <seealso cref="Selector"/> double click
/// to command binding attached behaviour.
/// </summary>
public class DoubleClickSelectorItem
{
  #region fields
  public static readonly DependencyProperty DoubleClickItemCommandProperty =
      DependencyProperty.RegisterAttached("DoubleClickItemCommand",
                                          typeof(ICommand),
                                          typeof(DoubleClickSelectorItem),
                                          new PropertyMetadata(null,
                                          DoubleClickSelectorItem.OnDoubleClickItemCommand));
  #endregion fields

  #region constructor
  /// <summary>
  /// Class constructor
  /// </summary>
  public DoubleClickSelectorItem()
  {

  }
  #endregion constructor

  #region properties
  #endregion properties

  #region methods
  #region attached dependency property methods
  public static ICommand GetDoubleClickItemCommand(DependencyObject obj)
  {
    return (ICommand)obj.GetValue(DoubleClickItemCommandProperty);
  }

  public static void SetDoubleClickItemCommand(DependencyObject obj, ICommand value)
  {
    obj.SetValue(DoubleClickItemCommandProperty, value);
  }
  #endregion attached dependency property methods

  private static void OnDoubleClickItemCommand(DependencyObject d, DependencyPropertyChangedEventArgs e)
  {
    var uiElement = d as Selector;

    // Remove the handler if it exist to avoid memory leaks
    if (uiElement != null)
      uiElement.MouseDoubleClick -= UIElement_MouseDoubleClick;

    var command = e.NewValue as ICommand;
    if (command != null)
    {
      // the property is attached so we attach the Drop event handler
      uiElement.MouseDoubleClick += UIElement_MouseDoubleClick;
    }
  }

  private static void UIElement_MouseDoubleClick(object sender, MouseButtonEventArgs e)
  {
    var uiElement = sender as Selector;

    // Sanity check just in case this was somehow send by something else
    if (uiElement == null)
      return;

    // Is there a selected item that was double clicked?
    if (uiElement.SelectedIndex == -1)
      return;

    ICommand doubleclickCommand = DoubleClickSelectorItem.GetDoubleClickItemCommand(uiElement);

    // There may not be a command bound to this after all
    if (doubleclickCommand == null)
      return;

    // Check whether this attached behaviour is bound to a RoutedCommand
    if (doubleclickCommand is RoutedCommand)
    {
      // Execute the routed command
      (doubleclickCommand as RoutedCommand).Execute(uiElement.SelectedItem, uiElement);
    }
    else
    {
      // Execute the Command as bound delegate
      doubleclickCommand.Execute(uiElement.SelectedItem);
    }            
  }
  #endregion methods
}

Usage in XAML:

<ListBox ItemsSource="{Binding CurrentItems}"
         behav:DoubleClickSelectorItem.DoubleClickItemCommand="{Binding Path=NavigateDownCommand}"
         />

Upvotes: 6

gls123
gls123

Reputation: 5617

If you are using databinding, then this problem is very easy to solve

<ListBox.ItemTemplate>
    <DataTemplate>
        <TextBlock Text="{Binding ObjectName}"
           MouseDown="TextBlock_MouseDown"/>
    </DataTemplate>
</ListBox.ItemTemplate>    

Then in your code behind, check for a double click as follows

private void TextBlock_MouseDown(object sender, MouseButtonEventArgs e)
{
    if (e.ClickCount>=2)
    { 
        ....
    }
}

If your double clicked item was not selected before the double click, then it wont appear selected in the event handler. Your logic within that handler needs to bear this in mind

Upvotes: 16

David Veeneman
David Veeneman

Reputation: 19132

It turns out there is a MouseDoubleClick event for the ListBox. I added this event to my ListBox and had the event handler process my task, copying the selected item to another ListBox. So, now whenever I double-click on an item, it gets copied.

Upvotes: 40

Ben Von Handorf
Ben Von Handorf

Reputation: 2336

You could always override the ListItem Control Template and handle the double click event inside the template, for example in an invisible border that contains the normal contents of the ListBox.

This article shows you how to use a ControlTemplate with a ListBoxItem. Beyond that, simply add the handler to the outermost element of your control template.

If you have Expression Blend, you can use it to extract the existing control template for you to modify so that you do not have to do as much work to ensure that the new list box behaves the same as the old.

Upvotes: 6

Related Questions