WPF ListBoxItem双击?

Dav*_*man 29 wpf wpf-controls

WPF ListBox没有DoubleClick事件,至少没有我能说的那么多.是否有针对此问题的解决方法,让我双击项目以让事件处理程序对其执行某些操作?谢谢你的帮助.

Dav*_*man 35

事实证明,ListBox有一个MouseDoubleClick事件.我将此事件添加到我的ListBox并让事件处理程序处理我的任务,将所选项目复制到另一个ListBox.所以,现在每当我双击某个项目时,它就会被复制.

  • 应该注意的是,当鼠标在控件内的任何位置双击时,会触发`ListBox.MouseDoubleClicked`事件.IE:这包括不在任何`ListBoxItem`上的双击. (9认同)
  • 甚至双击滚动条时会触发 (6认同)
  • @Marlos:不.如果单击列表框中的空白区域,则最后选择的项目将保持选中状态. (2认同)

mar*_*pet 29

可以将带有参数的命令绑定到ListBoxItems而不使用代码隐藏附加行为,只需使用InputBindingsa MouseBinding,如本答案中所示.

例如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>
Run Code Online (Sandbox Code Playgroud)

如果该命令是在相同的DataContext作为限定ItemsSourceListBox,它可以通过使用结合RelativeSource作为包括在例如结合.

  • 这是最好的解决方案.我尝试过EventToCommand之前没有用.InputBindings工作得很好.我在listbox datatemplate中的StackPanel上使用它们. (2认同)
  • 给这个开发者一些比特币! (2认同)
  • 从 TextBlock 引发事件的问题在于,它保存在不水平拉伸的 ContentPresenter 中,因此单击文本右侧的空间不会触发事件,即使 ListBoxItem 已突出显示整行。解决这个问题的唯一方法是覆盖模板,这似乎有点矫枉过正。 (2认同)

gls*_*123 13

如果您正在使用数据绑定,那么这个问题很容易解决

<ListBox.ItemTemplate>
    <DataTemplate>
        <TextBlock Text="{Binding ObjectName}"
           MouseDown="TextBlock_MouseDown"/>
    </DataTemplate>
</ListBox.ItemTemplate>    
Run Code Online (Sandbox Code Playgroud)

然后在你的代码后面,检查双击如下

private void TextBlock_MouseDown(object sender, MouseButtonEventArgs e)
{
    if (e.ClickCount>=2)
    { 
        ....
    }
}
Run Code Online (Sandbox Code Playgroud)

如果在双击之前未选中双击项目,则在事件处理程序中不会显示它.您在该处理程序中的逻辑需要记住这一点

  • 请注意,在此解决方案中,如果单击ListBoxItem但在文本块之外(如果是填充/边距),则不会触发该事件.这可能是也可能不是所希望的. (2认同)

Ben*_*orf 5

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

本文介绍如何将ControlTemplate与ListBoxItem一起使用.除此之外,只需将处理程序添加到控件模板的最外层元素即可.

如果您有Expression Blend,则可以使用它来提取现有的控件模板以供您修改,这样您就不必做太多工作来确保新列表框的行为与旧列表框相同.


use*_*608 5

我使用了 David 的上述答案(以“事实证明 ListBox 有一个 MouseDoubleClick 事件。”开头)来生成一个基于他的方法但通过附加行为实现的解决方案。

我并不是说你不应该有任何代码隐藏,因为我知道在某些情况下不应该以任何代价避免它。但是,这是另一个示例,说明如何将基于事件的解决方案转换为通过事件到命令绑定转换工作的 MVVM 兼容解决方案。

这是我附加的行为代码:

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
}
Run Code Online (Sandbox Code Playgroud)

XAML 中的用法:

<ListBox ItemsSource="{Binding CurrentItems}"
         behav:DoubleClickSelectorItem.DoubleClickItemCommand="{Binding Path=NavigateDownCommand}"
         />
Run Code Online (Sandbox Code Playgroud)