代码之家  ›  专栏  ›  技术社区  ›  Gus

如何在模板中点击按钮选择ListBoxItem?

  •  5
  • Gus  · 技术社区  · 16 年前

    我已将以下数据模板应用于列表框:

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

    3 回复  |  直到 15 年前
        1
  •  12
  •   Alex Paven    16 年前

    更好的方法是,因为您对选择项并不感兴趣(因为它很快就会被删除),将项本身作为CommandParameter传递给命令。

    或者,您可以使用代码隐藏或触发器以迂回的方式进行操作,但我不认为这是关键。例如:

    你能应付的按钮库。单击列表框上的事件,例如

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

    当然,您也可以将所有这些(或多或少完全相同)封装为一个可重用的 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),因此代码会变得更复杂,其好处是在datatemplate中单击的任何内容都会触发要选择的ListBoxItem,而不管它是否将事件标记为已处理。

    呵呵,我也试过只使用样式和触发器,但很快就变得难看了,我失去了兴趣(也失去了所有。。。错误的东西)。基本上可以解决,我想,但我真的不认为这是值得的麻烦。也许我忽略了一些显而易见的事情,不知道。

        2
  •  1
  •   Robert Rossney    16 年前

    使基础对象公开 RemoveCommand 属性,并绑定按钮的 Command

        3
  •  -1
  •   Velibor    9 年前

    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem" 
               BasedOn="{StaticResource {x:Type ListBoxItem}}">
            <Style.Triggers>
                <Trigger Property="IsKeyboardFocusWithin" Value="True">
                    <Setter Property="IsSelected" Value="True"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </ListBox.ItemContainerStyle>
    

    这是XAML唯一的方法。我还设置了BasedOn属性,以确保不会覆盖当前的ListBoxItem样式。

    推荐文章