Selecting a ListBoxItem when its inner ComboBox is focused
Asked Answered
A

3

12

I have a DataTemplate that will be a templated ListBoxItem, this DataTemplate has a ComboBox in it which when it has focus I want the ListBoxItem that this template represents to become selected, this looks right to me. but sadly enough it doesn't work =(

So the real question here is within a DataTemplate is it possible to get or set the value of the ListBoxItem.IsSelected property via a 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}" />
Anticlastic answered 22/9, 2009 at 12:23 Comment(0)
M
9

I found a solution for your problem.

The problem is that when you have a control on your listboxitem, and the control is clicked (like for inputting text or changing the value of a combobox), the ListBoxItem does not get selected.

this should do the job:

public class FocusableListBox : ListBox
{
    protected override bool IsItemItsOwnContainerOverride(object item)
    {
        return (item is FocusableListBoxItem);
    }

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

--> Use this FocusableListBox in stead of the default ListBox of WPF.

And use this 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);
        }
    }

}

A Treeview does also have this problem, but this solution does not work for a Treeview, 'cause SelectedItem of Treeview is readonly. So if you can help me out with the Treeview please ;-)

Malaise answered 22/9, 2009 at 12:49 Comment(2)
Solved my problem. i was actually quite stumped on this one. interesting approach to the solution. i'm quite curious if there is a way to do this in XAML ?Anticlastic
no idea if it is possible in xaml. I'm glad it just works in code :)Malaise
J
9

I found that I preferred to use this:

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

Simple and works for all the listboxitems, regardless of what's inside.

Jimmiejimmy answered 4/1, 2012 at 9:46 Comment(2)
Your answer was helpful every time I got this problem. But now I have a Delete Button on the ListBoxItem which is Focusable=False. In this case when clicking on this button the old SelectedItem is deleted instead of selecting the item on which Delete button was clicked and then delete it.Sierra
Your answer works but after clicking on a button or any other control my selected index resets to -1Tempura
M
0

No idea why your trigger don't work. To catch the get focus event of the combo box (or any control inside a listbox item) you can use attached routed events. You could put the code also in a derived listbox if you need this behavior in other parts of your application.

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>

Code behind hooking up to all got focus events.

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);
            }
        }
    }
}
Melanism answered 24/9, 2009 at 16:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.