Sélectionner un élément Textbox dans une liste ne change pas l'élément sélectionné de la liste

j'ai une liste WPF qui affiche une liste de boîtes de textes. Lorsque je clique sur la zone de texte, la sélection Listbox ne change pas. Je dois cliquer à côté de la zone de texte pour sélectionner l'élément listbox. Y a-t-il une propriété que je dois définir pour la boîte de texte pour transférer l'événement de clic à la liste?

43
demandé sur Dave Clemmer 2009-03-17 12:29:46

14 réponses

assurez-vous d'utiliser TargetType approprié: ListViewItem, ListBoxItem ou TreeViewItem.

<Style TargetType="ListViewItem">
    <Style.Triggers>
        <Trigger Property="IsKeyboardFocusWithin" Value="true">
            <Setter Property="IsSelected" Value="true" />
        </Trigger>
    </Style.Triggers>
</Style>
37
répondu Grazer 2011-11-03 05:03:42

nous utilisons le style suivant pour définir un PreviewGotKeyboardFocus qui gère tous les événements de TextBox control et ComboBoxes et tel:

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

et ensuite nous sélectionnons la ligne en code derrière:

    protected void SelectCurrentItem(object sender, KeyboardFocusChangedEventArgs e)
    {
        ListViewItem item = (ListViewItem) sender;
        item.IsSelected = true;
    }
35
répondu Arcturus 2009-12-14 08:42:22

Je n'ai pas assez de représentants pour commenter, donc je poste mon commentaire comme réponse. La solution de Grazer ci-dessus ne fonctionne pas dans les cas où vous avez un autre contrôle tel qu'un Button qui nécessite le SelectedItem . C'est parce que selon le Style Trigger , le IsKeyboardFocusWithin devient faux quand vous cliquez sur ce Button , et le SelectedItem devient nul.

6
répondu dotnetzen 2013-12-23 01:07:43

j'ai utilisé similaire à la solution de Robert, mais sans code derrière (en utilisant le comportement attaché).

De le faire", 151980920"

D'abord. Créer une classe séparée axée sur le comportement:


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

namespace MyBehaviours
{
    public class FocusBehaviour
    {
        #region IsFocused
        public static bool GetIsFocused(Control control)
        {
            return (bool) control.GetValue(IsFocusedProperty);
        }

        public static void SetIsFocused(Control control, bool value)
        {
            control.SetValue(IsFocusedProperty, value);
        }

        public static readonly DependencyProperty IsFocusedProperty = DependencyProperty.RegisterAttached(
            "IsFocused", 
            typeof(bool),
            typeof(FocusBehaviour), 
            new UIPropertyMetadata(false, IsFocusedPropertyChanged));

        public static void IsFocusedPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var control = sender as Control;
            if (control == null || !(e.NewValue is bool))
                return;
            if ((bool)e.NewValue && !(bool)e.OldValue)
                control.Focus();
        }

        #endregion IsFocused

        #region IsListBoxItemSelected

        public static bool GetIsListBoxItemSelected(Control control)
        {
            return (bool) control.GetValue(IsListBoxItemSelectedProperty);
        }

        public static void SetIsListBoxItemSelected(Control control, bool value)
        {
            control.SetValue(IsListBoxItemSelectedProperty, value);
        }

        public static readonly DependencyProperty IsListBoxItemSelectedProperty = DependencyProperty.RegisterAttached(
            "IsListBoxItemSelected", 
            typeof(bool),
            typeof(FocusBehaviour), 
            new UIPropertyMetadata(false, IsListBoxItemSelectedPropertyChanged));

        public static void IsListBoxItemSelectedPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var control = sender as Control;
            DependencyObject p = control;
            while (p != null && !(p is ListBoxItem))
            {
                p = VisualTreeHelper.GetParent(p);
            } 

            if (p == null)
                return;

            ((ListBoxItem)p).IsSelected = (bool)e.NewValue;
        }

        #endregion IsListBoxItemSelected
    }
}

à la Seconde. Ajouter un style dans la section Ressources (mon style est arrondi noir sur focus). Note setter pour Focus behaviour.IsListBoxItemSelected property. Vous devez le mentionner dans xmlns:behave="clr-namespace:MyBehaviours"

"

    <Style x:Key="PreviewTextBox" BasedOn="{x:Null}" TargetType="{x:Type TextBox}">
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="Padding" Value="1"/>
        <Setter Property="AllowDrop" Value="true"/>
        <Setter Property="Background" Value="White"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TextBox}">
                    <Border
                        Margin="6,2,0,4"
                        BorderBrush="#FFBDBEBD"
                        BorderThickness="1"
                        CornerRadius="8"
                        Background="White"
                        VerticalAlignment="Stretch"
                        HorizontalAlignment="Stretch"
                        MinWidth="100"
                        x:Name="bg">
                        <ScrollViewer 
                            x:Name="PART_ContentHost" 
                            SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsKeyboardFocusWithin" Value="True">
                            <Setter Property="Background" TargetName="bg" Value="Black"/>
                            <Setter Property="Background" Value="Black"/><!-- we need it for caret, it is black on black elsewise -->
                            <Setter Property="Foreground" Value="White"/>
                            <Setter Property="behave:FocusBehaviour.IsListBoxItemSelected" Value="True"/>
                        </Trigger>

                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

"

troisième. (en option, pour l'inverse)

vous rencontrerez, si ce n'est pas n'importe quelle tâche inverse - en se concentrant sur TextBox lorsque ListBoxItem est sélectionné. Je recommande d'utiliser une autre propriété de la classe de comportement, IsFocused. Voici un modèle pour ListBoxItem , s'il vous plaît noter Property="behave:FocusBehaviour.IsFocused" et FocusManager.IsFocusScope="True"

    <DataTemplate x:Key="YourKey" DataType="{x:Type YourType}">
            <Border
            Background="#FFF7F3F7"
            BorderBrush="#FFBDBEBD"
            BorderThickness="0,0,0,1"
            FocusManager.IsFocusScope="True"
            x:Name="bd"
            MinHeight="40">
                <TextBox
                    x:Name="textBox"
                    Style="{StaticResource PreviewTextBox}"
                    Text="{Binding Value}" />
        </Border>
        <DataTemplate.Triggers>
            <DataTrigger
                Binding="{Binding IsSelected,RelativeSource={RelativeSource AncestorType=ListBoxItem}}"
                Value="True">
                <Setter
                    TargetName="textBox"
                    Property="behave:FocusBehaviour.IsFocused" 
                    Value="True" />
            </DataTrigger>
        </DataTemplate.Triggers>
    </DataTemplate>
3
répondu Ben 2010-11-09 22:34:36

j'utilise un gestionnaire de classe pour régler ce comportement. Le faire de cette façon va corriger toutes les vues de liste dans l'application. Je ne sais pas pourquoi ce n'est pas le comportement par défaut.

dans votre application.XAML.cs, ajouter ce qui suit à OnStartup:

protected override void OnStartup(StartupEventArgs e)
    {
        EventManager.RegisterClassHandler(typeof (ListViewItem), 
                                          ListViewItem.PreviewGotKeyboardFocusEvent,
                                          new RoutedEventHandler((x,_) => (x as ListViewItem).IsSelected = true));
    }
3
répondu oillio 2011-06-16 02:01:22

est-ce qu'il y a une propriété que j'ai besoin de définir pour la boîte de texte pour transmettre l'événement de clic à la liste?

ce n'est pas une propriété simple, mais vous pouvez gérer le GotFocus événement sur votre TextBox , puis utiliser VisualTreeHelper pour trouver le ListBoxItem et le sélectionner:

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;
}
2
répondu Robert Macnee 2009-03-17 16:01:09

la façon la plus simple que j'ai pu trouver pour faire ceci est d'utiliser L'événement précédent MouseDown et de définir la propriété IsSelected du parent Templé. Depuis que les événements de prévisualisation bulle vers le bas, le ListBoxItem va traiter l'événement dès que l'utilisateur clique sur la textbox, combobox, ou tout autre contrôle que vous mettez l'événement sur.

une bonne chose à ce sujet est que vous pouvez utiliser le même événement pour tous les types de contrôles car ils dérivent tous de L'élément Framework. Également, définir IsSelected (au lieu de définir SelectedItem) fera que plusieurs éléments seront sélectionnés lorsque vous définirez le mode de sélection de la liste à "Extended", ce qui pourrait ou non être ce que vous recherchez.

c'est à dire:

code c#

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"/>
    ...
1
répondu Mark Synowiec 2009-04-04 00:26:34
1
répondu Natrium 2017-05-23 12:34:14

ce qui suit est une simplification de la réponse de @Ben sans avoir à Outrepasser le Dataemplate. Il peut même être appliqué comme un style statique. Testé avec un ListView contenant un GridView > GridViewColumn > TextBox .

exemple:

<ListView.Resources>
    <Style TargetType="{x:Type ListViewItem}">
        <Style.Triggers>
            <Trigger Property="IsKeyboardFocusWithin" Value="True">
                <Setter Property="IsSelected" Value="True"></Setter>
            </Trigger>
        </Style.Triggers>
    </Style>
</ListView.Resources>
1
répondu Graeme Wicksted 2017-01-31 20:50:27

la Listbox gère la sélection des articles mais ne connaît pas le focus de la textbox intégrée. Si vous voulez changer la sélection à chaque fois qu'une boîte de texte reçoit le focus d'entrée, alors vous devez changer la sélection de liste manuellement, afaik.

0
répondu Joey 2009-03-17 09:34:22

Je ne suis pas entièrement sûr que vous voudriez mettre la sélection directement comme décrit dans la réponse précédente parce que je pense qu'il briserait le multi-sélection et quelques autres scénarios

. Vous pourriez essayer de restyling un bouton comme ci-dessous et voir ce qui se passe.

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

0
répondu Steven 2009-03-20 16:44:36

votre manque de précision sur votre situation initiale. Mais je suppose que vous utilisez la datation et un ItemTemplate. Thats imho un moyen facile de le faire, ainsi que si votre débutant sur ce sujet. Cela devrait fonctionner:

<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) */
}
0
répondu Marcel B 2009-03-26 02:03:25

essayez ce code:

foreach (object item in this.listBox1.Items) {
    if (textbox1.text.equals(item.toString())) {
        //show error message; break
    }
}
0
répondu lincy oommen 2012-10-22 21:23:03

Vieille discussion, mais peut-être que ma réponse aide les autres....

la solution de Ben a le même problème que la solution de Grazer. La mauvaise chose est que la sélection dépend de la mise au point [clavier] de la boîte de texte. Si vous avez un autre contrôle sur votre boîte de dialogue (c'est-à-dire un bouton), le focus est perdu en cliquant sur le bouton et le listboxitem n'est pas sélectionné (SelectedItem == null). Vous avez donc un comportement différent pour cliquer l'élément (en dehors de la zone de texte) et cliquer dans le zone de texte. C'est très fastidieux à manipuler et très étrange.

je suis sûr qu'il n'y a pas de solution pure XAML pour ça. Nous avons besoin de code-behind pour cela. La solution est proche de ce que Mark a suggéré.

(dans mon exemple, J'utilise ListViewItem au lieu de ListBoxItem, mais la solution fonctionne pour les deux).

code-behind:

private void Element_PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
        var frameworkElement = sender as FrameworkElement;
        if (frameworkElement != null)
        {
            var item = FindParent<ListViewItem>(frameworkElement);
            if (item != null)
                item.IsSelected = true;
        }
    }

avec FindParent (tiré de http://www.infragistics.com/community/blogs/blagunas/archive/2013/05/29/find-the-parent-control-of-a-specific-type-in-wpf-and-silverlight.aspx ):

public static T FindParent<T>(DependencyObject child) where T : DependencyObject
    {
        //get parent item
        DependencyObject parentObject = VisualTreeHelper.GetParent(child);

        //we've reached the end of the tree
        if (parentObject == null) return null;

        //check if the parent matches the type we're looking for
        T parent = parentObject as T;
        if (parent != null)
            return parent;

        return FindParent<T>(parentObject);
    }

dans mon Datemplate:

<TextBox Text="{Binding Name}"
        PreviewMouseDown="Element_PreviewMouseDown"/>
0
répondu Sven Bardos 2015-01-08 22:17:29