148 votes

Comment effectuer une sélection de case à cocher en un seul clic dans une grille de données WPF ?

J'ai un DataGrid dont la première colonne est une colonne de texte et la seconde une colonne de case à cocher. Ce que je veux, c'est que si je clique sur la case à cocher. Elle doit être cochée.

Mais, il faut deux clics pour être sélectionné, au premier clic la cellule est sélectionnée, au second clic la case à cocher est cochée. Comment faire pour que la case à cocher soit cochée/décochée en un seul clic ?

J'utilise WPF 4.0. Les colonnes de la grille de données sont générées automatiquement.

4 votes

Duplicata de : stackoverflow.com/questions/1225836/ mais celui-ci a un meilleur titre

200voto

Pour une case à cocher DataGrid à clic unique, vous pouvez simplement placer un contrôle de case à cocher ordinaire à l'intérieur de la grille. DataGridTemplateColumn et mettre UpdateSourceTrigger=PropertyChanged .

<DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
        <CheckBox IsChecked="{Binding Path=IsSelected, UpdateSourceTrigger=PropertyChanged}" />
    </DataTemplate>
</DataGridTemplateColumn.CellTemplate>

4 votes

WOW - Je suis content d'avoir lu jusqu'au bout. Ceci fonctionne parfaitement et est considérablement moins compliqué, IMO ceci devrait être marqué comme la réponse.

2 votes

Cela fonctionne également pour les ComboBox. Comme dans : bien, BIEN mieux que DataGridComboBoxColumn.

2 votes

Ce n'est pas le cas lorsque j'utilise la barre d'espace pour cocher/décocher et les flèches pour passer à une autre cellule.

65voto

Jim Adorno Points 239

J'ai résolu ce problème avec le Style suivant :

<Style TargetType="DataGridCell">
     <Style.Triggers>
         <Trigger Property="IsMouseOver" Value="True">
             <Setter Property="IsEditing" Value="True" />
         </Trigger>
     </Style.Triggers>
 </Style>

Il est bien sûr possible d'adapter ce système pour des colonnes spécifiques...

8 votes

Joli. Je l'ai changé en un MultiTrigger et j'ai ajouté une condition pour ReadOnly=False mais l'approche de base a fonctionné pour mon cas simple où la navigation au clavier n'est pas importante.

0 votes

L'ajout de ce style à ma grille soulève une exception : Operation is not valid while ItemsSource is in use. Accédez et modifiez les éléments avec ItemsControl.ItemsSource à la place.

0 votes

J'ai résolu le problème en utilisant un déclencheur sur DataGridRow et non sur la cellule et en forçant IsSelected à true au passage de la souris, ce n'est pas la meilleure approche, mais ça marche.

28voto

Priidu Neemre Points 483

Tout d'abord, je sais que c'est une vieille question, mais j'ai quand même pensé que je devais essayer d'y répondre.

J'ai eu le même problème il y a quelques jours et je suis tombé sur une solution étonnamment courte (cf. ce blog ). En gros, tout ce que vous devez faire, c'est remplacer l'élément DataGridCheckBoxColumn dans votre XAML avec ce qui suit :

<DataGridTemplateColumn Header="MyCheckBoxColumnHeader">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <CheckBox HorizontalAlignment="Center" VerticalAlignment="Center" IsChecked="{Binding Path=MyViewModelProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

L'avantage de cette solution est évident : elle est uniquement en XAML ; elle vous évite donc de surcharger votre code-back avec une logique d'interface utilisateur supplémentaire et vous aide à conserver votre statut aux yeux des zélateurs de MVVM ;).

1 votes

Cette réponse est similaire à celle de Konstantin Salavatov et celle-ci a fonctionné pour moi. +1 pour avoir inclus l'exemple de code alors que la sienne ne l'a pas fait. Merci pour cette bonne réponse à une vieille question.

1 votes

Le problème, c'est que si vous le faites avec des colonnes combobox, le petit bouton déroulant sera visible pour toutes les cellules de cette colonne, tout le temps. Pas seulement lorsque vous cliquez sur la cellule.

18voto

surfen Points 2703

Basé sur le blog référencé dans la réponse de Goblin, mais modifié pour fonctionner en .NET 4.0 et avec le mode Row-Selection.

Notez qu'il accélère également l'édition des colonnes DataGridComboBoxColumn - en entrant en mode édition et en affichant la liste déroulante en cas de simple clic ou de saisie de texte.

XAML :

        <Style TargetType="{x:Type DataGridCell}">
            <EventSetter Event="PreviewMouseLeftButtonDown" Handler="DataGridCell_PreviewMouseLeftButtonDown" />
            <EventSetter Event="PreviewTextInput" Handler="DataGridCell_PreviewTextInput" />
        </Style>

Code-behind :

    private void DataGridCell_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        DataGridCell cell = sender as DataGridCell;
        GridColumnFastEdit(cell, e);
    }

    private void DataGridCell_PreviewTextInput(object sender, TextCompositionEventArgs e)
    {
        DataGridCell cell = sender as DataGridCell;
        GridColumnFastEdit(cell, e);
    }

    private static void GridColumnFastEdit(DataGridCell cell, RoutedEventArgs e)
    {
        if (cell == null || cell.IsEditing || cell.IsReadOnly)
            return;

        DataGrid dataGrid = FindVisualParent<DataGrid>(cell);
        if (dataGrid == null)
            return;

        if (!cell.IsFocused)
        {
            cell.Focus();
        }

        if (cell.Content is CheckBox)
        {
            if (dataGrid.SelectionUnit != DataGridSelectionUnit.FullRow)
            {
                if (!cell.IsSelected)
                    cell.IsSelected = true;
            }
            else
            {
                DataGridRow row = FindVisualParent<DataGridRow>(cell);
                if (row != null && !row.IsSelected)
                {
                    row.IsSelected = true;
                }
            }
        }
        else
        {
            ComboBox cb = cell.Content as ComboBox;
            if (cb != null)
            {
                //DataGrid dataGrid = FindVisualParent<DataGrid>(cell);
                dataGrid.BeginEdit(e);
                cell.Dispatcher.Invoke(
                 DispatcherPriority.Background,
                 new Action(delegate { }));
                cb.IsDropDownOpen = true;
            }
        }
    }

    private static T FindVisualParent<T>(UIElement element) where T : UIElement
    {
        UIElement parent = element;
        while (parent != null)
        {
            T correctlyTyped = parent as T;
            if (correctlyTyped != null)
            {
                return correctlyTyped;
            }

            parent = VisualTreeHelper.GetParent(parent) as UIElement;
        }
        return null;
    }

0 votes

Cette solution a été la plus efficace pour moi. Mon ViewModel lié ne se mettait pas à jour avec les autres solutions.

0 votes

@surfen, Si j'ai plusieurs pages qui contiennent une grille de données, dois-je mettre le style et le code ci-dessus dans chaque page et son code derrière, est-il possible d'utiliser le style et le code dans un endroit commun au lieu de les créer dans chaque page ?

0 votes

Pourquoi avez-vous besoin de distribuer une action vide ?

11voto

Goblin Points 4612

C'est pour 3.5sp1, je sais - mais ça devrait fonctionner sous 4.0 : Vinsibal .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X