2010-03-30 197 views
25

WPF ListBox没有DoubleClick事件,至少没有我所知道的。是否有解决此问题的方法,可以让我双击某个项目以使事件处理程序对它执行某些操作?谢谢你的帮助。WPF ListBoxItem双击?

+4

看看这个问题:http://stackoverflow.com/questions/821564/double-click-a-list-item – Eclipse 2010-03-30 18:13:53

回答

4

您始终可以重写ListItem控件模板并处理模板内的双击事件,例如在包含ListBox常规内容的不可见边框中。

This article shows you how to use a ControlTemplate with a ListBoxItem。除此之外,只需将处理程序添加到控件模板的最外层元素即可。

如果您有Expression Blend,可以使用它来提取现有的控件模板供您修改,以便您不必执行尽可能多的工作来确保新列表框的行为与旧的行为相同。

+0

找到了一个更好的解决方案 - 见下文。我现在正在离开公认的答案,只是因为我很欣赏Ben在这个问题上的帮助。 – 2010-04-04 17:24:06

31

原来有一个ListBox的MouseDoubleClick事件。我将这个事件添加到我的ListBox并让事件处理程序处理我的任务,将选定的项目复制到另一个ListBox。所以,现在每当我双击一个项目时,它都会被复制。

+1

这真的很方便。我没有为我的列表使用数据模板(只是想显示一些文本),并且这节省了我不得不将我的文本包装在模板化控件中。 – 2012-05-09 13:09:17

+7

应该注意的是,当ListBox.MouseDoubleClicked事件发生时,鼠标会触发在控件内的任何位置双击。 IE:这包括不在任何'ListBoxItem'上的双击。 – 2013-03-26 20:14:47

+1

@ChrisKerekes你是对的。作为参考,我认为这可以通过使用if(listBox.SelectedIndex == -1)return;'来解决。 – Marlos 2013-08-20 17:23:52

13

如果您使用数据绑定,那么这个问题是很容易在你的代码来解决

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

那么后面,检查双击如下

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

如果你的双次点击项目在双击之前没有被选中,那么它在事件处理程序中不会显示出来。您在该处理程序中的逻辑需要考虑到这一点

+2

注意这个解决方案,如果你点击ListBoxItem但在文本块之外(在填充/边距的情况下),事件不会触发。这可能会也可能不会是理想的。 – Clay 2014-02-25 17:18:59

+0

^为了解决这个问题,只需给TextBlock一个'Background',就像'Transparent'一样,然后你可以在TextBlock边界内的任意位置双击。 – 2015-05-22 09:20:36

+0

谢谢,这对我来说比ListBox的内置MouseDoubleClick事件更好的解决方案,因为它将双击限制为实际项目而不会扩展黑客行为。 – germanSharper 2016-09-05 13:36:51

3

我已经使用了David的上述答案(它以“事实证明存在ListBox的MouseDoubleClick事件”开头),以生成基于他的方法,但实施与附加行为。

我不是说你不应该有任何代码背后,因为我知道有些情况下,不应该为任何代价避免。但是,这是您如何将基于事件的解决方案转换为符合MVVM标准的解决方案的另一个示例,该解决方案通过Event来命令绑定转换。

这是我的附加行为的代码:在XAML

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 
} 

用法:

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

这是可能的,而不使用代码隐藏附加的行为与参数ListBoxItem s到结合命令,简单地通过使用InputBindingsMouseBinding,如之前在this answer中所示。

ListBoxMouseBindingLeftDoubleClick

<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> 

如果该命令被在相同的DataContext作为ListBoxItemsSource定义,它可以通过使用RelativeSource结合作为包括在实施例的限制。

+2

那是最好的解决方案。我尝试过之前没有工作的EventToCommand。 InputBindings完美工作。我在ListBox数据模板的StackPanel上使用它们。 – BlueM 2016-03-23 16:29:51

+0

好的有意义的解决方案。 – AnjumSKhan 2017-03-28 10:37:07

+0

这是迄今为止最明智,最健壮的解决方案。 – 2017-12-29 01:23:30