如何在单击模板中的按钮时选择ListBoxItem?

Gus*_*nti 5 wpf command

我将以下数据模板应用于ListBox:

<DataTemplate x:Key="MyTemplate" DataType="{x:Type DAL:Person}">
    <StackPanel Orientation="Horizontal">
        <Button Content="X" Command="{x:Static cmd:MyCommands.Remove}"/>
        <TextBlock Text="{Binding Person.FullName}" />
    </StackPanel>
</DataTemplate>
Run Code Online (Sandbox Code Playgroud)

当我单击按钮时,命令被触发但ListBoxItem未被选中.如何强制它被选中,以便我可以在"执行"方法中获取所选项目?

谢谢

Ale*_*ven 11

一个更好的方法,因为你真的不想选择项目(因为它会很快被删除)将把项目本身作为CommandParameter传递给Command.

或者,您可以使用代码隐藏或使用触发器以迂回方式进行,但我认为不会如此.例如:

你可以处理列表框上的ButtonBase.Click事件,比如

<ListBox ButtonBase.Click="lb_Click"
...
Run Code Online (Sandbox Code Playgroud)

然后在你的代码后面,这样做:

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

获取单击的绑定项,因为按钮的datacontext是从其模板化项继承的,然后是ListBox的ItemContainerGenerator中的实际自动生成的ListBoxItem,并将IsSelected属性设置为true.我认为这是最快捷,最简单的方法之一.也适用于模板中的多个ButtonBase派生对象.

当然,您还可以更好地将所有这些(或多或少完全相同)封装为可重用行为:

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

你可以像这样使用它:

<ListBox xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" ...>
    <i:Interaction.Behaviors>
        <local:SelectItemOnButtonClick />
    </i:Interaction.Behaviors>
</ListBox>
Run Code Online (Sandbox Code Playgroud)

添加错误处理代码,如至少是null检查,当然 - 不希望像这样轰炸你的应用程序这样简单的事情.

要理解该问题,该按钮会将处理它的所有鼠标事件(MouseDown/Click)的Handled属性设置为true,以便ListBoxItem不会考虑它们.你也可以将MouseDown事件附加到ListBox并向上走可视树,直到你到达父ListBoxItem,但这更棘手......呃,如果你很好奇,你可以阅读这篇文章,知道为什么,基本上你' ll还会遇到FrameworkContentElements(它也会响应MouseDown),因此代码会变得更复杂,而且在datatemplate内部点击的任何东西都会触发ListBoxItem被选中,无论它是否将事件标记为已处理.

嘿,我也尝试用风格和触发器专门做它,但它快速变得丑陋,我失去了兴趣(并且失去了所有......错误的东西).基本上它可以解决,我想,但我认为这不值得打扰.也许我忽略了一些显而易见的事情,不知道.