【问题标题】:WPF ListBoxItem double-click?WPF ListBoxItem 双击?
【发布时间】:2011-02-02 14:19:22
【问题描述】:

WPF 列表框没有 DoubleClick 事件,至少据我所知没有。是否有解决此问题的方法可以让我双击某个项目以让事件处理程序对其进行处理?感谢您的帮助。

【问题讨论】:

标签: wpf wpf-controls


【解决方案1】:

可以在不使用代码隐藏附加行为的情况下将带有参数的命令绑定到ListBoxItems,只需使用InputBindingsMouseBinding ,如前面this answer所示。

例如ListBoxMouseBinding 用于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>

如果命令在与ListBoxItemsSource 相同的DataContext 中定义,则可以使用示例中包含的RelativeSource 绑定来绑定它。

【讨论】:

  • 这是最好的解决方案。我试过 EventToCommand 之前没有用。 InputBindings 完美地工作。我在列表框数据模板内的 StackPanel 上使用它们。
  • 给这个开发者一些比特币!
  • 这个答案应该受到保护,谢谢!我也是! ?
  • 从 TextBlock 引发事件的问题是它被保存在不水平拉伸的 ContentPresenter 中,因此单击文本右侧的空间不会触发事件,即使ListBoxItem 突出显示了整行。解决这个问题的唯一方法是覆盖模板,这似乎有点过头了。
  • Robin,将 Horizo​​ntalContentAlignment="Stretch" 添加到 ListBox 将起作用
【解决方案2】:

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

【讨论】:

  • 这真的很方便。我没有为我的列表使用数据模板(只是想显示一些文本),这样我就不必将我的文本包装在模板控件中
  • 应该注意ListBox.MouseDoubleClicked 事件会在鼠标在控件内的任意位置双击时触发。 IE:这包括不在任何ListBoxItem 上的双击。
  • @ChrisKerekes 你是对的。作为参考,我认为这可以通过使用if (listBox.SelectedIndex == -1) return;来解决。
  • @Marlos:不。如果您单击列表框中的空白区域,则最后选择的项目保持选中状态。
  • 甚至在双击滚动条时触发
【解决方案3】:

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

<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)
    { 
        ....
    }
}

如果您双击的项目在双击之前没有被选中,那么它不会在事件处理程序中显示为选中。您在该处理程序中的逻辑需要牢记这一点

【讨论】:

  • 请注意此解决方案,如果您在 ListBoxItem 内但在文本块外单击(在填充/边距的情况下),则不会触发该事件。这可能是可取的,也可能是不可取的。
  • ^ 要解决这个问题,只需给 TextBlock 一个 Background,如 Transparent,然后您可以双击 TextBlock 范围内的任意位置。
  • 谢谢,这对我来说是比 ListBox 的内置 MouseDoubleClick-event 更好的解决方案,因为它将双击限制为实际项目而无需扩展黑客攻击。
  • @MikeEason Background=透明对我不起作用,因为这不会使文本块填充宽度。
【解决方案4】:

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

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

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

【讨论】:

  • 找到了一个效果更好的解决方案——见下文。我将按原样保留已接受的答案,只是因为我感谢 Ben 在这个问题上的帮助。
【解决方案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
}

在 XAML 中的用法:

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

【讨论】:

    【解决方案6】:

    根据MSDN article,您可以为列表框中的每个项目添加一个处理程序,如下所示:

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

    在后面的代码中,您将处理双击。然后,您可以通过处理程序中的sender.DataContext 访问DataContext。由于双击选择了一个项目,您还可以使用SelectedItem 属性或ListBox 上的类似属性。

    我个人更喜欢允许重定向到命令的Behavior 解决方案,但我不确定如何实现。

    【讨论】:

      【解决方案7】:

      ListBox 现在有一个双击事件。

      【讨论】:

        【解决方案8】:

        关于双击事件使用:

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

        【讨论】:

        • 如果列表中有一个列标题,您也可以通过双击列标题返回System.Windows.Controls.TextBlock,所以我不确定这是否可行而不会导致异常。
        【解决方案9】:

        由于我使用的是 SelectionMode="Multiple",因此当前的答案在我的情况下均无效,因此我只想与您分享我发现的实现此功能的最简洁方式。

        首先,我为包含的 ListBoxItem 创建了一个处理程序:

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

        然后,每当一个 ListBoxItem 被添加到 ListBox 时,Handler 就会被添加到 ListBoxItem:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-05-22
          • 1970-01-01
          • 2011-03-23
          • 2020-10-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多