当内部ComboBox获得焦点时如何选择一个ListBoxItem

12

我有一个DataTemplate,将用作模板化的ListBoxItem,这个DataTemplate中有一个ComboBox,当它获得焦点时,我希望代表该模板的ListBoxItem被选中,这对我来说看起来很正确。但是可悲的是,它不起作用 =(

所以这里真正的问题是,在DataTemplate中是否可能通过DataTemplate.Trigger获取或设置ListBoxItem.IsSelected属性的值?

<DataTemplate x:Key="myDataTemplate" 
              DataType="{x:Type local:myTemplateItem}">

 <Grid x:Name="_LayoutRoot">
     <ComboBox x:Name="testComboBox" />
 </Grid>

 <DataTemplate.Triggers>
     <Trigger Property="IsFocused" value="true" SourceName="testComboBox">
         <Setter Property="ListBoxItem.IsSelected" Value="true" />
     </Trigger>
 </DataTemplate.Triggers>

</DataTemplate>

<ListBox ItemTemplate="{StaticResource myDataTemplate}" />
3个回答

9
我为你的问题找到了一个解决方案。
问题在于当你在列表框项上有一个控件时,当控件被点击(例如输入文本或更改组合框的值)时,列表框项不会被选中。
以下代码可解决此问题:
public class FocusableListBox : ListBox
{
    protected override bool IsItemItsOwnContainerOverride(object item)
    {
        return (item is FocusableListBoxItem);
    }

    protected override System.Windows.DependencyObject GetContainerForItemOverride()
    {
        return new FocusableListBoxItem();
    }
}

--> 使用这个 FocusableListBox 替代 WPF 的默认 ListBox。

并使用这个 ListBoxItem:

public class FocusableListBoxItem : ListBoxItem
{
    public FocusableListBoxItem()
    {
        GotFocus += new RoutedEventHandler(FocusableListBoxItem_GotFocus);
    }


    void FocusableListBoxItem_GotFocus(object sender, RoutedEventArgs e)
    {
        object obj = ParentListBox.ItemContainerGenerator.ItemFromContainer(this);
        ParentListBox.SelectedItem = obj;
    }

    private ListBox ParentListBox
    {
        get
        {
            return (ItemsControl.ItemsControlFromItemContainer(this) as ListBox);
        }
    }

}

一个“树形视图”也存在这个问题,但是该解决方案不适用于“树形视图”,因为“树形视图”的“SelectedItem”是“只读的”。如果您能帮我解决“树形视图”的问题,那就太好了;-)

1
解决了我的问题。对于这个问题,我确实感到非常困惑。 解决方案的方法很有趣。我很好奇是否有一种在XAML中实现这一点的方式? - AppleDrink
不知道在XAML中是否可能。很高兴它在代码中可以正常工作 :) - Natrium

9
我发现我更喜欢使用这个: ```html

我发现我更喜欢使用这个:

```
<Style  TargetType="ListBoxItem">
    <Style.Triggers>
        <Trigger Property="IsKeyboardFocusWithin" Value="True">
             <Setter Property="IsSelected" Value="True"></Setter>
        </Trigger>
    </Style.Triggers>
</Style>

简单易用,适用于所有列表框选项,无论其中包含什么内容。


每次我遇到这个问题时,你的回答都很有帮助。但现在我的ListBoxItem上有一个Focusable=False的Delete按钮。在这种情况下,当点击此按钮时,旧的SelectedItem被删除,而不是选择单击Delete按钮的项目,然后将其删除。 - Vishal
2
你的答案是正确的,但是在点击按钮或其他控件后,我的选定索引会重置为-1。 - Dev

0

不知道为什么您的触发器无法正常工作。要捕获组合框(或列表框项内的任何控件)的获取焦点事件,可以使用附加路由事件。如果您需要在应用程序的其他部分中使用此行为,则还可以将代码放入派生列表框中。

XAML:

<Window x:Class="RoutedEventDemo.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Specialized="clr-namespace:System.Collections.Specialized;assembly=System"
    xmlns:System="clr-namespace:System;assembly=mscorlib"
    Height="300" Width="300">

    <Window.Resources>

        <DataTemplate x:Key="myDataTemplate">
            <Grid>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding}" Margin="5,0"/>
                    <ComboBox Width="50">
                        <ComboBoxItem>AAA</ComboBoxItem>
                        <ComboBoxItem>BBB</ComboBoxItem>
                    </ComboBox>
                </StackPanel>
            </Grid>
        </DataTemplate>

    </Window.Resources>

    <Grid>

        <ListBox ItemTemplate="{StaticResource myDataTemplate}">
            <ListBox.ItemsSource>
                <Specialized:StringCollection>
                    <System:String>Item 1</System:String>
                    <System:String>Item 2</System:String>
                    <System:String>Item 3</System:String> 
                </Specialized:StringCollection>
            </ListBox.ItemsSource>
        </ListBox>

    </Grid>
</Window>

代码背后连接到所有获取焦点事件。

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace RoutedEventDemo
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();

            EventManager.RegisterClassHandler(typeof(UIElement),
                                              GotFocusEvent,
                                              new RoutedEventHandler(OnGotFocus));
        }

        private static void OnGotFocus(object sender, RoutedEventArgs e)
        {
            // Check if element that got focus is contained by a listboxitem and
            // in that case selected the listboxitem.

            DependencyObject parent = e.OriginalSource as DependencyObject;
            while (parent != null)
            {
                ListBoxItem clickedOnItem = parent as ListBoxItem;
                if (clickedOnItem != null)
                {
                    clickedOnItem.IsSelected = true;
                    return;
                }

                parent = VisualTreeHelper.GetParent(parent);
            }
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接