【问题标题】:Selecting a ListBoxItem when its inner ComboBox is focused当其内部 ComboBox 获得焦点时选择一个 ListBoxItem
【发布时间】:2010-11-30 09:28:36
【问题描述】:

我有一个 DataTemplate,它将是一个模板化的 ListBoxItem,这个 DataTemplate 有一个 ComboBox 在其中,当它有焦点时,我想要这个模板的 ListBoxItem 代表被选中,这对我来说是正确的。但遗憾的是它不起作用 =(

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

<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}" />

【问题讨论】:

    标签: wpf xaml listbox datatemplate triggers


    【解决方案1】:

    我找到了解决您问题的方法。

    问题是,当您在列表框项上有一个控件时,单击该控件(例如输入文本或更改组合框的值)时,列表框项不会被选中。

    这应该可以完成工作:

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

    Treeview 也有这个问题,但这个解决方案不适用于Treeview,因为TreeviewSelectedItemreadonly。 因此,如果您可以帮助我解决 Treeview 问题,请 ;-)

    【讨论】:

    • 解决了我的问题。我实际上对这个感到很困惑。解决方案的有趣方法。我很好奇 XAML 中是否有办法做到这一点?
    • 不知道在 xaml 中是否可行。我很高兴它只在代码中工作:)
    【解决方案2】:

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

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

    简单且适用于所有列表框项,无论里面有什么。

    【讨论】:

    • 每次我遇到这个问题时,您的回答都很有帮助。但是现在我在 ListBoxItem 上有一个删除按钮,它是 Focusable=False。在这种情况下,当单击此按钮时,旧的 SelectedItem 将被删除,而不是选择单击删除按钮的项目然后将其删除。
    • 您的答案有效,但在单击按钮或任何其他控件后,我选择的索引重置为 -1
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-31
      • 2023-04-04
      • 2011-03-13
      • 2014-05-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多