更好的方法是,将项目本身作为 CommandParameter 传递给 Command,因为您对选择项目并不感兴趣(因为无论如何它都会很快被删除)。
或者,您可以使用代码隐藏或触发器以迂回的方式进行,但我认为这不是重点。例如:
您可以处理列表框上的 ButtonBase.Click 事件,例如
<ListBox ButtonBase.Click="lb_Click"
...
然后在你的代码后面,这样做:
private void lb_Click(object sender, RoutedEventArgs e)
{
object clicked = (e.OriginalSource as FrameworkElement).DataContext;
var lbi = lb.ItemContainerGenerator.ContainerFromItem(clicked) as ListBoxItem;
lbi.IsSelected = true;
}
这会得到单击的绑定项,因为按钮的数据上下文是从它的模板项继承的,然后是从 ListBox 的 ItemContainerGenerator 中实际自动生成的 ListBoxItem,并将 IsSelected 属性设置为 true。我认为这是最快和最简单的方法之一。也适用于模板中的多个 ButtonBase 派生对象。
当然,您也可以更好地将所有这些(或多或少完全相同)封装为可重复使用的Behavior:
public class SelectItemOnButtonClick : Behavior<ListBox>
{
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(handler), true);
}
protected override void OnDetaching()
{
this.AssociatedObject.RemoveHandler(ButtonBase.ClickEvent, new RoutedEventHandler(handler));
base.OnDetaching();
}
private void handler(object s, RoutedEventArgs e)
{
object clicked = (e.OriginalSource as FrameworkElement).DataContext;
var lbi = AssociatedObject.ItemContainerGenerator.ContainerFromItem(clicked) as ListBoxItem;
lbi.IsSelected = true;
}
}
你可以这样使用它:
<ListBox xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" ...>
<i:Interaction.Behaviors>
<local:SelectItemOnButtonClick />
</i:Interaction.Behaviors>
</ListBox>
当然,添加错误处理代码,例如至少为空检查 - 不希望这样简单的事情轰炸您的应用程序。
为了理解这个问题,按钮将所有作用于它的鼠标事件(MouseDown/Click)的 Handled 属性设置为 true,因此 ListBoxItem 不会考虑它们。您还可以将 MouseDown 事件附加到 ListBox 并向上移动可视化树,直到到达父 ListBoxItem 但这要棘手得多……嗯,如果您好奇,可以阅读 this article 以了解原因,基本上是您' 还会遇到 FrameworkContentElements(它也响应 MouseDown),因此代码会变得更加复杂,好处是在数据模板内单击的任何内容都会触发 ListBoxItem 被选中,无论它是否将事件标记为已处理。
嘿,我也尝试只使用样式和触发器来完成它,但它很快就变得丑陋了,我失去了兴趣(并且忘记了所有......错误的事情)。我认为基本上它可以解决,但我认为这不值得费心。也许我忽略了一些明显的东西,不知道。