2010-02-03 15 views
6

Dodałem DataTemplate do klasy ListBox związać moją kolekcję:Wybierz ListBoxItem jeśli TextBox w ItemTemplate dostaje skupić

<ListBox x:Name="lstEmails" Height="259" Margin="12,0,12,41" Width="276" 
     SelectionChanged="lstEmails_SelectionChanged"> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <StackPanel Orientation="Horizontal"> 
       <Label Visibility="Hidden" Content="{Binding ID}"></Label> 
       <TextBox Width="200" Text="{Binding EmailAddress}"></TextBox> 
      </StackPanel> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

To robi dokładnie to, co chcę robić. Chociaż po kliknięciu na TextBox, ListBox nie ustawia automatycznie powiązanego ListItem jako Selected. Mógłbym to zrobić w kodzie, ale wolałbym użyć tego jako komponentu (nie ma wtedy niespodzianek).

Jakieś pomysły, jak to osiągnąć?


To chyba nie działa, nie pozwala na kliknięcie. Czy coś przeoczyłem. Oto mój nowy XAML.

<UserControl.Resources> 
    <!--<TextBox x:Key="TB" x:Name="TextBoxInsideListBoxItemTemplate"> 
     <TextBox.Style>--> 
      <Style TargetType="{x:Type TextBox}"> 
       <Setter Property="IsHitTestVisible" Value="False" /> 
       <Style.Triggers> 
        <DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ListBoxItem}, AncestorLevel=1}}" 
                Value="True"> 
         <Setter Property="IsHitTestVisible" Value="True" /> 
        </DataTrigger> 
       </Style.Triggers> 
      </Style> 
     <!--</TextBox.Style> 
    </TextBox>--> 
</UserControl.Resources> 
<Grid> 
    <ListBox x:Name="lstEmails" Height="259" Margin="12,0,12,41" Width="276" SelectionChanged="lstEmails_SelectionChanged"> 
     <ListBox.ItemTemplate> 
      <DataTemplate> 
       <StackPanel Orientation="Horizontal"> 
        <!--<Label Visibility="Hidden" Content="{Binding ID}"></Label>--> 
        <TextBox Width="220" Text="{Binding EmailAddress}" > 
        </TextBox> 
        <!--<TextBox Width="220" Text="{Binding EmailAddress}" GotFocus="TextBox_GotFocus"></TextBox>--> 
       </StackPanel> 
      </DataTemplate> 
     </ListBox.ItemTemplate> 
    </ListBox> 
    <Button Width="20" Margin="12,0,0,12" Name="btnAdd" VerticalAlignment="Bottom" Click="btnAdd_Click" Height="23" HorizontalAlignment="Left">+</Button> 
    <Button Width="20" HorizontalAlignment="Left" Margin="30,0,0,12" Name="btnRemove" VerticalAlignment="Bottom" Click="btnRemove_Click" Height="23">-</Button> 
    <Button Height="23" HorizontalAlignment="Right" Margin="0,0,12,12" Name="btnApply" VerticalAlignment="Bottom" Width="49" Click="btnApply_Click">Apply</Button> 
</Grid> 

Myślę, że dwukrotne kliknięcie to dobra funkcjonalność.

Odpowiedz

3

Jeśli masz wiele instancji ListBox, możesz rozważyć użycie niestandardowego listbox (przez wyprowadzenie go z ListBox). Zobacz the explanation here.


Lub użyć tego włamać jeśli masz tylko 1 (lub tylko niewielką liczbę) takiego ListBox i nie chcesz, aby utworzyć oddzielną klasę dla że:

<TextBox x:Name="TextBoxInsideListBoxItemTemplate" ... > 

    <TextBox.Style> 
     <Style TargetType="{x:Type TextBox}"> 
      <Setter Property="IsHitTestVisible" Value="False" /> 
      <Style.Triggers> 
       <DataTrigger 
         Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, 
        AncestorType={x:Type ListBoxItem}, AncestorLevel=1}}" 
         Value="True"> 
        <Setter Property="IsHitTestVisible" Value="True" /> 
       </DataTrigger> 
      </Style.Triggers> 
     </Style> 
    </TextBox.Style> 

</TextBox> 

Należy pamiętać, że będziesz musiał kliknąć jeszcze raz, aby edytować tekst w TextBox (co jest w rzeczywistości fajne według mnie).

7

Możesz wyzwolić na nieruchomości IsKeyboardFocusWithin w ItemContainerStyle i ustawić IsSelected na true.

<ListBox.ItemContainerStyle> 
    <Style TargetType="{x:Type ListBoxItem}"> 
     <Style.Triggers> 
      <DataTrigger Binding="{Binding IsKeyboardFocusWithin, RelativeSource={RelativeSource Self}}" Value="True"> 
       <DataTrigger.EnterActions> 
        <BeginStoryboard> 
         <Storyboard> 
          <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="(ListBoxItem.IsSelected)"> 
           <DiscreteBooleanKeyFrame KeyTime="0" Value="True"/> 
          </BooleanAnimationUsingKeyFrames> 
         </Storyboard> 
        </BeginStoryboard> 
       </DataTrigger.EnterActions> 
      </DataTrigger> 
     </Style.Triggers> 
    </Style> 
</ListBox.ItemContainerStyle> 

Można też użyć Setter zamiast jednej animacji klatek ale wtedy wybór zostaną utracone ponownie raz ostrość pozostawia ListBox:

<ListBox.ItemContainerStyle> 
    <Style TargetType="{x:Type ListBoxItem}"> 
     <Style.Triggers> 
      <DataTrigger Binding="{Binding IsKeyboardFocusWithin, RelativeSource={RelativeSource Self}}" Value="True"> 
       <Setter Property="IsSelected" Value="True"/> 
      </DataTrigger> 
     </Style.Triggers> 
    </Style> 
</ListBox.ItemContainerStyle> 
+0

Świetne! Uratował mnie dzisiaj! –

+0

To świetne rozwiązanie, z tym wyjątkiem, że nie jest kompatybilne z trybami wyboru Extended i Multiple. – xvpower

0

miałem sytuację, w której dobór odpowiednich element listbox zmieniłby swój układ, więc kontrola mogła odejść od kursora przed zwolnieniem przycisku myszy. Nie znalazłem lepszego rozwiązania niż użycie niewielkiego opóźnienia w Storyboard, jeśli chcę zachować wszystko w Xaml.

Co ważniejsze, GotKeyboardFocus wydaje się działać lepiej niż IsKeyboardFocusWithin dla wielokrotnych wyborów.

<EventTrigger RoutedEvent="GotKeyboardFocus"> 
    <BeginStoryboard> 
     <Storyboard> 
      <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsSelected"> 
       <DiscreteBooleanKeyFrame KeyTime="00:00:00.3" Value="True"/> 
      </BooleanAnimationUsingKeyFrames> 
     </Storyboard> 
    </BeginStoryboard> 
</EventTrigger>