tags:

views:

2157

answers:

7

I Have a wpf Listbox that display's a list of textboxes. When I click on the Textbox the Listbox selection does not change. I have to click next to the TextBox to select the listbox item. Is there some property I need to set for the Textbox to forward the click event to the Listbox?

A: 

The Listbox handles item selection but does not know about focus of the textbox embedded within. If you want to change the selection whenever a textbox gets input focus then you need to change the listbox selection manually, afaik.

Joey
A: 

Is there some property I need to set for the Textbox to forward the click event to the Listbox?

It's not a simple property, but you can handle the GotFocus event on your TextBox, then use VisualTreeHelper to find the ListBoxItem and select it:

private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
    TextBox myTextBox = sender as TextBox;
    DependencyObject parent = VisualTreeHelper.GetParent(myTextBox);
    while (!(parent is ListBoxItem))
    {
        parent = VisualTreeHelper.GetParent(parent);
    }
    ListBoxItem myListBoxItem = parent as ListBoxItem;
    myListBoxItem.IsSelected = true;
}
Robert Macnee
A: 

I'm not entirely sure you would want to set the selection directly as described in the previous answer because I think it would break multiselection and some other scenerios

. You might want to try restyling a button like below and see what happens.

<Button ClickMode="Pressed" Focusable="False">
<Button.Template>
 <ControlTemplate>  // change the template to get rid of all the default chrome 
  <Border Background="Transparent"> // Button won't be clickable without some kind of background set
   <ContentPresenter />
  </Border>
 </ControlTemplate>
</Button.Template>
<TextBox />

Steven
A: 

Your not very specific about your initial situation. But i assume that you use DataBinding and an ItemTemplate. Thats imho an easy way to do this, as well if your beginner on this topic. This should work:

<ListBox ItemsSource="{Binding someDataCollection}" Name="myListBox">
   <ListBox.ItemTemplate>
      <DataTemplate>
         <TextBox Text="{Binding datafield}" Tag="{Binding .}"
                  GotFocus="TextBox_GotFocus"/>
      </DataTemplate>
   </ListBox.ItemTemplate>
</ListBox>


private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
   myListBox.SelectedItem = (sender as TextBox).Tag; /* Maybe you need to cast to the type of the objects contained in the collection(bound as ItemSource above) */
}
Marcel Benthin
+1  A: 

The simplest way I've been able to find to do this is to use the PreviewMouseDown event and set the IsSelected property of the templated parent. Since the preview events bubble down, the ListBoxItem will process the event as soon as the user clicks the textbox, combobox, or any other control you set the event on.

One nice thing about this is that you can use the same event for all types of controls since they all derive from Framework element. Also, setting IsSelected (instead of setting the SelectedItem) will cause multiple items to be selected when you set the SelectionMode of the listbox to "Extended", which could or could not be what you're looking for.

ie:

c# code

private void Element_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    ((sender as FrameworkElement).TemplatedParent as ListBoxItem).IsSelected = true;
}

xaml

    ...
    <ComboBox PreviewMouseDown="Element_PreviewMouseDown"/>
    <TextBox PreviewMouseDown="Element_PreviewMouseDown"/>
    ...
Mark Synowiec
+2  A: 

We use the following style to set a PreviewGotKeyboardFocus which handles all events of TextBox control and ComboBoxes and such:

    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <EventSetter Event="PreviewGotKeyboardFocus" Handler="SelectCurrentItem"/>
        </Style>
    </ListView.ItemContainerStyle>

And then we select the row in code behind:

    protected void SelectCurrentItem(object sender, KeyboardFocusChangedEventArgs e)
    {
        ListViewItem item = (ListViewItem) sender;
        item.IsSelected = true;
    }
Arcturus
This definitely seems the best method. I have a deeply nested hierarchy, ListBoxes contained within other ListBoxes, and various controls contained inside those. This method just works, because it only uses the ListBoxItem and not the contained control.One suggested change though - it's simpler to just select the item directly:item.IsSelected = true
Niall
Excellent suggestion! I have changed the code..
Arcturus