【发布时间】:2011-02-02 14:19:22
【问题描述】:
WPF 列表框没有 DoubleClick 事件,至少据我所知没有。是否有解决此问题的方法可以让我双击某个项目以让事件处理程序对其进行处理?感谢您的帮助。
【问题讨论】:
标签: wpf wpf-controls
WPF 列表框没有 DoubleClick 事件,至少据我所知没有。是否有解决此问题的方法可以让我双击某个项目以让事件处理程序对其进行处理?感谢您的帮助。
【问题讨论】:
标签: wpf wpf-controls
可以在不使用代码隐藏或附加行为的情况下将带有参数的命令绑定到ListBoxItems,只需使用InputBindings和MouseBinding ,如前面this answer所示。
例如ListBox 和MouseBinding 用于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>
如果命令在与ListBox 的ItemsSource 相同的DataContext 中定义,则可以使用示例中包含的RelativeSource 绑定来绑定它。
【讨论】:
原来 ListBox 有一个 MouseDoubleClick 事件。我将此事件添加到我的 ListBox 并让事件处理程序处理我的任务,将所选项目复制到另一个 ListBox。所以,现在每当我双击一个项目时,它都会被复制。
【讨论】:
ListBox.MouseDoubleClicked 事件会在鼠标在控件内的任意位置双击时触发。 IE:这包括不在任何ListBoxItem 上的双击。
if (listBox.SelectedIndex == -1) return;来解决。
如果你使用数据绑定,那么这个问题很容易解决
<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)
{
....
}
}
如果您双击的项目在双击之前没有被选中,那么它不会在事件处理程序中显示为选中。您在该处理程序中的逻辑需要牢记这一点
【讨论】:
Background,如 Transparent,然后您可以双击 TextBlock 范围内的任意位置。
您始终可以覆盖 ListItem 控件模板并处理模板内的双击事件,例如在包含 ListBox 正常内容的不可见边框中。
This article shows you how to use a ControlTemplate with a ListBoxItem。除此之外,只需将处理程序添加到控件模板的最外层元素即可。
如果您有 Expression Blend,您可以使用它来提取现有的控件模板供您修改,这样您就不必做太多工作来确保新列表框与旧列表框的行为相同。
【讨论】:
我使用了 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}"
/>
【讨论】:
根据MSDN article,您可以为列表框中的每个项目添加一个处理程序,如下所示:
<ListBox>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<EventSetter Event="MouseDoubleClick" Handler="ListBoxItem_MouseDoubleClick"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
在后面的代码中,您将处理双击。然后,您可以通过处理程序中的sender.DataContext 访问DataContext。由于双击选择了一个项目,您还可以使用SelectedItem 属性或ListBox 上的类似属性。
我个人更喜欢允许重定向到命令的Behavior 解决方案,但我不确定如何实现。
【讨论】:
ListBox 现在有一个双击事件。
【讨论】:
关于双击事件使用:
if (e.OriginalSource.GetType().ToString() == "System.Windows.Controls.TextBlock")
DoubleClickDoneOnItem();
【讨论】:
System.Windows.Controls.TextBlock,所以我不确定这是否可行而不会导致异常。
由于我使用的是 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);
}
【讨论】: