100 votes

Modification en un seul clic dans une grille de données WPF

Je souhaite que l'utilisateur puisse mettre la cellule en mode édition et mettre en évidence la ligne dans laquelle se trouve la cellule d'un simple clic. Par défaut, il s'agit d'un double clic.

Comment puis-je remplacer ou mettre en œuvre cette fonction ?

0 votes

Utilisez-vous le DataGrid qui se trouve dans le WPF Toolkit ?

4 votes

Serait-il possible pour vous de nous donner un peu plus d'informations sur ce que vous avez essayé et sur ce qui ne fonctionne pas ?

82voto

Micael Bergeron Points 423

Voici comment j'ai résolu ce problème :

<DataGrid DataGridCell.Selected="DataGridCell_Selected" 
          ItemsSource="{Binding Source={StaticResource itemView}}">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Nom" Binding="{Binding Path=Name}"/>
        <DataGridTextColumn Header="Age" Binding="{Binding Path=Age}"/>
    </DataGrid.Columns>
</DataGrid>

Cette grille de données est liée à une CollectionViewSource (contenant des données factices). Personne objets).

C'est là que la magie opère : DataGridCell.Selected="DataGridCell_Selected" .

J'accroche simplement l'événement Selected Event de la cellule du DataGrid, et j'appelle BeginEdit() sur le DataGrid.

Voici le code derrière pour le gestionnaire d'événement :

private void DataGridCell_Selected(object sender, RoutedEventArgs e)
{
    // Lookup for the source to be DataGridCell
    if (e.OriginalSource.GetType() == typeof(DataGridCell))
    {
        // Starts the Edit on the row;
        DataGrid grd = (DataGrid)sender;
        grd.BeginEdit(e);
    }
}

8 votes

Vous pouvez contourner le problème des rangées déjà sélectionnées en définissant l'attribut SelectionUnit de la DataGrid pour Cell .

0 votes

Supposons que j'ai une TextBox dans ma DataGridCell. Après avoir appelé grd.BeginEdit(e) Je veux que la TextBox de cette cellule ait le focus. Comment puis-je faire cela ? J'ai essayé d'appeler FindName("txtBox") à la fois sur le DataGridCell et le DataGrid, mais il renvoie null pour moi.

0 votes

GotFocus="DataGrid_GotFocus" semble manquer ?

45voto

user2134678 Points 71

La réponse de Micael Bergeron a été un bon début pour moi pour trouver une solution qui fonctionne pour moi. Pour permettre l'édition en un seul clic également pour les cellules de la même ligne qui sont déjà en mode édition, j'ai dû l'ajuster un peu. L'utilisation de SelectionUnit Cell n'était pas une option pour moi.

Au lieu d'utiliser l'événement DataGridCell.Selected Event qui n'est déclenché que lors du premier clic sur la cellule d'une ligne, j'ai utilisé l'événement DataGridCell.GotFocus Event.

<DataGrid DataGridCell.GotFocus="DataGrid_CellGotFocus" />

Si vous faites cela, vous aurez toujours la bonne cellule focalisée et en mode édition, mais aucun contrôle dans la cellule ne sera focalisé, ce que j'ai résolu comme suit

private void DataGrid_CellGotFocus(object sender, RoutedEventArgs e)
{
    // Lookup for the source to be DataGridCell
    if (e.OriginalSource.GetType() == typeof(DataGridCell))
    {
        // Starts the Edit on the row;
        DataGrid grd = (DataGrid)sender;
        grd.BeginEdit(e);

        Control control = GetFirstChildByType<Control>(e.OriginalSource as DataGridCell);
        if (control != null)
        {
            control.Focus();
        }
    }
}

private T GetFirstChildByType<T>(DependencyObject prop) where T : DependencyObject
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(prop); i++)
    {
        DependencyObject child = VisualTreeHelper.GetChild((prop), i) as DependencyObject;
        if (child == null)
            continue;

        T castedProp = child as T;
        if (castedProp != null)
            return castedProp;

        castedProp = GetFirstChildByType<T>(child);

        if (castedProp != null)
            return castedProp;
    }
    return null;
}

3 votes

Les cases à cocher ne semblent pas fonctionner pour moi ? je dois toujours double-cliquer dessus

9voto

m-y Points 12871

De : http://wpf.codeplex.com/wikipage?title=Single-Click%20Editing

XAML :

<!-- SINGLE CLICK EDITING -->
<Style TargetType="{x:Type dg:DataGridCell}">
    <EventSetter Event="PreviewMouseLeftButtonDown" Handler="DataGridCell_PreviewMouseLeftButtonDown"></EventSetter>
</Style>

CODE-BEHIND :

//
// SINGLE CLICK EDITING
//
private void DataGridCell_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    DataGridCell cell = sender as DataGridCell;
    if (cell != null && !cell.IsEditing && !cell.IsReadOnly)
    {
        if (!cell.IsFocused)
        {
            cell.Focus();
        }
        DataGrid dataGrid = FindVisualParent<DataGrid>(cell);
        if (dataGrid != null)
        {
            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;
                }
            }
        }
    }
}

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;
}

1 votes

Ça ne marche pas dans certains cas, et c'est plus compliqué que la solution de Micael Bergeron.

0 votes

Pour moi, c'était presque la solution. J'ai dû ajouter un gestionnaire d'événement "PreviewMouseLeftButtonUp" et y mettre exactement le même code.

0 votes

Cela ne fonctionne pas non plus une fois que vous avez une combobox. le clic de prévisualisation voit les clics sur la popup de la combobox, puis l'appel de cell.focus fait tout foirer. la solution la plus simple est d'ajouter une section qui regarde la source originale des événements de la souris, en utilisant FindVisualParent sur cela pour voir si c'est à l'intérieur de la grille de données. si non, ne faites pas le reste du travail.

7voto

Andikki Points 220

La solution de http://wpf.codeplex.com/wikipage?title=Single-Click%20Editing a bien fonctionné pour moi, mais je l'ai activé pour chaque DataGrid utilisant un Style défini dans un ResourceDictionary. Pour utiliser les gestionnaires dans les dictionnaires de ressources, vous devez y ajouter un fichier code-behind. Voici comment procéder :

Il s'agit d'un DataGridStyles.xaml Dictionnaire des ressources :

    <ResourceDictionary x:Class="YourNamespace.DataGridStyles"
                x:ClassModifier="public"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Style TargetType="DataGrid">
            <!-- Your DataGrid style definition goes here -->

            <!-- Cell style -->
            <Setter Property="CellStyle">
                <Setter.Value>
                    <Style TargetType="DataGridCell">                    
                        <!-- Your DataGrid Cell style definition goes here -->
                        <!-- Single Click Editing -->
                        <EventSetter Event="PreviewMouseLeftButtonDown"
                                 Handler="DataGridCell_PreviewMouseLeftButtonDown" />
                    </Style>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>

Notez l'attribut x:Class dans l'élément Root. Créez un fichier de classe. Dans cet exemple, ce sera DataGridStyles.xaml.cs . Mettez ce code à l'intérieur :

using System.Windows.Controls;
using System.Windows;
using System.Windows.Input;

namespace YourNamespace
{
    partial class DataGridStyles : ResourceDictionary
    {

        public DataGridStyles()
        {
          InitializeComponent();
        }

     // The code from the myermian's answer goes here.
}

1 votes

Le lien est mort (limite de 15 caractères)

1voto

GrantA Points 11

Il y a deux problèmes avec la réponse de l'utilisateur2134678. L'un est très mineur et n'a aucun effet fonctionnel. L'autre est assez important.

Le premier problème est que le GotFocus est en fait appelé contre le DataGrid, et non le DataGridCell dans la pratique. Le qualificatif DataGridCell dans le XAML est redondant.

Le principal problème que j'ai trouvé avec la réponse est que le comportement de la touche Entrée est cassé. La touche Entrée devrait vous faire passer à la cellule suivante sous la cellule actuelle dans le comportement normal d'un DataGrid. Cependant, ce qui se passe en coulisses, c'est que l'événement GotFocus est appelé deux fois. Une fois lorsque la cellule actuelle perd le focus, et une fois lorsque la nouvelle cellule gagne le focus. Mais tant que BeginEdit est appelé sur cette première cellule, la cellule suivante ne sera jamais activée. Le résultat est que vous avez une édition en un clic, mais toute personne qui ne clique pas littéralement sur la grille va être gênée, et un concepteur d'interface utilisateur ne devrait pas supposer que tous les utilisateurs utilisent des souris. (Les utilisateurs de claviers peuvent en quelque sorte contourner le problème en utilisant la touche Tab, mais cela signifie tout de même qu'ils doivent passer par des étapes qu'ils ne devraient pas avoir à franchir).

La solution à ce problème ? Gérer l'événement KeyDown pour la cellule et, si la touche est la touche Entrée, définir un indicateur qui empêche BeginEdit de se déclencher sur la première cellule. Maintenant, la touche Entrée se comporte comme elle le devrait.

Pour commencer, ajoutez le style suivant à votre DataGrid :

<DataGrid.Resources>
    <Style TargetType="{x:Type DataGridCell}" x:Key="SingleClickEditingCellStyle">
        <EventSetter Event="KeyDown" Handler="DataGridCell_KeyDown" />
    </Style>
</DataGrid.Resources>

Appliquez ce style à la propriété "CellStyle" des colonnes pour lesquelles vous voulez activer le one-click.

Ensuite, dans le code qui suit, vous avez ce qui suit dans votre gestionnaire GotFocus (notez que j'utilise VB ici parce que c'est ce que notre client "demande de grille de données en un clic" voulait comme langage de développement) :

Private _endEditing As Boolean = False

Private Sub DataGrid_GotFocus(ByVal sender As Object, ByVal e As RoutedEventArgs)
    If Me._endEditing Then
        Me._endEditing = False
        Return
    End If

    Dim cell = TryCast(e.OriginalSource, DataGridCell)

    If cell Is Nothing Then
        Return
    End If

    If cell.IsReadOnly Then
        Return
    End If

    DirectCast(sender, DataGrid).BeginEdit(e)
    .
    .
    .

Ensuite, vous ajoutez votre gestionnaire de l'événement KeyDown :

Private Sub DataGridCell_KeyDown(ByVal sender As Object, ByVal e As KeyEventArgs)
    If e.Key = Key.Enter Then
        Me._endEditing = True
    End If
End Sub

Vous disposez maintenant d'un DataGrid qui n'a pas modifié le comportement fondamental de l'implémentation prête à l'emploi, mais qui prend en charge l'édition en un seul clic.

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