Je veux que l'utilisateur puisse mettre la cellule en mode d'édition et mettre en évidence la ligne dans laquelle la cellule est contenue en un seul clic. Par défaut, il s'agit d'un double clic.
Comment puis-je remplacer ou mettre en œuvre cela?
Ce DataGrid est lié à un CollectionViewSource (contenant des objets Personne factice ).
La magie opère ici: DataGridCell.Selected = "DataGridCell_Selected" .
J'accroche simplement l'événement sélectionné de la cellule DataGrid et j'appelle BeginEdit () sur le DataGrid.
Voici le code derrière le gestionnaire d'événements:
privatevoidDataGridCell_Selected(object sender,RoutedEventArgs e){// Lookup for the source to be DataGridCellif(e.OriginalSource.GetType()==typeof(DataGridCell)){// Starts the Edit on the row;DataGrid grd =(DataGrid)sender;
grd.BeginEdit(e);}}
Vous pouvez contourner le problème de ligne déjà sélectionné en définissant la SelectionUnitpropriété sur le DataGrid sur Cell.
Matt Winckler
Supposons que j'ai une zone de texte dans mon DataGridCell. Après avoir appelé grd.BeginEdit(e), je veux que la zone de texte de cette cellule ait le focus. Comment puis je faire ça? J'ai essayé d'appeler FindName("txtBox")à la fois le DataGridCell et le DataGrid, mais il renvoie null pour moi.
user1214135
GotFocus = "DataGrid_GotFocus" semble manquer?
synergetic
4
Cela fonctionne bien, mais je ne recommanderais pas de le faire. J'ai utilisé cela dans mon projet et j'ai décidé de revenir au comportement DG standard. À l'avenir, lorsque votre DG grandira et deviendra complexe, vous rencontrerez des problèmes de validation, l'ajout de nouvelles lignes et d'autres comportements étranges.
white.zaz
1
@ white.zaz était-il satisfait du client après avoir rétrogradé au comportement DG standard? Parce que la principale raison posée à cette question était que l'édition dans les capacités standard de DG n'est pas conviviale car il faut trop de clics pour que DG passe en mode d'édition.
AEMLoviji
42
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 était déjà en mode d'édition, j'ai dû l'ajuster un peu. Utiliser SelectionUnit Cell n'était pas une option pour moi.
Au lieu d'utiliser l'événement DataGridCell.Selected qui n'est déclenché que pour la première fois que l'utilisateur clique sur la cellule d'une ligne, j'ai utilisé l'événement DataGridCell.GotFocus.
Si vous le faites, 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 ceci
privatevoidDataGrid_CellGotFocus(object sender,RoutedEventArgs e){// Lookup for the source to be DataGridCellif(e.OriginalSource.GetType()==typeof(DataGridCell)){// Starts the Edit on the row;DataGrid grd =(DataGrid)sender;
grd.BeginEdit(e);Control control =GetFirstChildByType<Control>(e.OriginalSourceasDataGridCell);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)asDependencyObject;if(child ==null)continue;
T castedProp = child as T;if(castedProp !=null)return castedProp;
castedProp =GetFirstChildByType<T>(child);if(castedProp !=null)return castedProp;}returnnull;}
cela ne fonctionne pas dans certains cas, et c'est plus compliqué que la solution Micael Bergerons.
SwissCoder
Pour moi, c'était presque la solution. J'avais besoin d'ajouter un gestionnaire d'événements "PreviewMouseLeftButtonUp" et y mettre exactement le même code.
Néstor Sánchez A.
cela ne fonctionne pas non plus une fois que vous avez une combobox. le clic de prévisualisation voit des clics sur la fenêtre contextuelle de la zone de liste déroulante, puis l'appel cell.focus vire tout. La solution la plus simple consiste à ajouter une section qui examine la source d'origine des événements de souris, en utilisant FindVisualParent pour voir si elle se trouve à l'intérieur de la grille de données. sinon, ne faites aucun des autres travaux.
John Gardner
7
La solution de http://wpf.codeplex.com/wikipage?title=Single-Click%20Editing a très bien fonctionné pour moi, mais je l'ai activée pour chaque DataGrid en utilisant un style défini dans un ResourceDictionary. Pour utiliser des gestionnaires dans des dictionnaires de ressources, vous devez y ajouter un fichier code-behind. Voici comment procéder:
Ceci est un dictionnaire de ressources DataGridStyles.xaml :
<ResourceDictionaryx:Class="YourNamespace.DataGridStyles"x:ClassModifier="public"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><StyleTargetType="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 racine. Créez un fichier de classe. Dans cet exemple, ce serait DataGridStyles.xaml.cs . Mettez ce code à l'intérieur:
usingSystem.Windows.Controls;usingSystem.Windows;usingSystem.Windows.Input;namespaceYourNamespace{partialclassDataGridStyles:ResourceDictionary{publicDataGridStyles(){InitializeComponent();}// The code from the myermian's answer goes here.}
Cela ne fonctionne pas si une zone de liste déroulante est utilisée comme modèle d'édition, je suppose que d'autres, comme la case à cocher qui capture les événements de la souris, seraient également cassées
Steve
Pour moi, cela fonctionne avec les colonnes de la zone de liste déroulante, mais la zone de texte de la "nouvelle ligne d'élément" (dernière ligne) a un comportement étrange: au premier clic, j'obtiens le focus d'entrée et je peux saisir des éléments. Quand je déplace la souris hors de la cellule , la valeur de la zone de texte disparaît. Lorsque vous tapez plus loin, le texte nouvellement entré est correctement enregistré (il crée une nouvelle entrée comme souhaité). Cela se produit également avec un ComboboxColumn.
FrankM
Au départ, cela semble fonctionner correctement, mais totalement gâché mon Datagrid, lorsque j'essaie de trier, toutes ces valeurs sont disparues, sans ce code, tout fonctionne bien avec le tri.
Chandraprakash
3
Je l'ai résolu en ajoutant un déclencheur qui définit la propriété IsEditing de DataGridCell sur True lorsque la souris est dessus. Cela a résolu la plupart de mes problèmes. Cela fonctionne aussi avec les comboboxes.
Ne fonctionne pas ... il perd l'édition dès que la souris quitte la cellule. Donc, vous 1) faites un clic gauche sur la cellule que vous souhaitez modifier. 2) déplacez la souris à l'écart 3) Commencez à taper. Votre saisie ne fonctionne pas car la cellule n'est plus en mode édition.
Skarsnik
1
ne fonctionne pas pour moi non plus. m'empêche de modifier la zone de texte
Blechdose
Mais il y a un problème avec cette approche, j'avais verrouillé la 1ère colonne pour l'édition, avec cette approche, cela rend la 1ère colonne également éditable!
Chandraprakash
3
Je recherche une cellule d'édition en un seul clic dans MVVM et c'est une autre façon de le faire.
Il y a deux problèmes avec la réponse de user2134678. L'un est très mineur et n'a aucun effet fonctionnel. L'autre est assez significatif.
Le premier problème est que le GotFocus est en fait appelé par rapport au DataGrid, et non au DataGridCell en 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é. Entrée devrait vous déplacer vers la cellule suivante sous la cellule actuelle dans un comportement DataGrid normal. Cependant, ce qui se passe réellement dans les coulisses, c'est que l'événement GotFocus sera appelé deux fois. Une fois sur la cellule actuelle perdant la focalisation, et une fois sur la nouvelle cellule gagnant la concentration. 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 modification en un clic, mais quiconque ne clique pas littéralement sur la grille sera incommodé, et un concepteur d'interface utilisateur ne doit pas supposer que tous les utilisateurs utilisent des souris. (Les utilisateurs de clavier peuvent en quelque sorte le contourner en utilisant Tab, mais cela signifie toujours qu'ils sautent à travers des cerceaux dont ils ne devraient pas avoir besoin.)
Alors, la solution à ce problème? Gérez l'événement KeyDown pour la cellule et si la clé est la clé Entrée, définissez un indicateur qui empêche BeginEdit de se déclencher sur la première cellule. Maintenant, la touche Entrée se comporte comme il se doit.
Pour commencer, ajoutez le style suivant à votre DataGrid:
Appliquez ce style à la propriété "CellStyle" des colonnes pour lesquelles vous souhaitez activer en un clic.
Ensuite, dans le code derrière 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):
Ensuite, vous ajoutez votre gestionnaire pour l'événement KeyDown:
PrivateSubDataGridCell_KeyDown(ByVal sender AsObject,ByVal e AsKeyEventArgs)If e.Key=Key.EnterThenMe._endEditing =TrueEndIfEndSub
Vous disposez maintenant d'un DataGrid qui n'a modifié aucun comportement fondamental de l'implémentation prête à l'emploi et qui prend en charge l'édition en un seul clic.
Je sais que je suis un peu en retard à la fête mais j'ai eu le même problème et j'ai trouvé une solution différente:
publicclassDataGridTextBoxColumn:DataGridBoundColumn{publicDataGridTextBoxColumn():base(){}protectedoverrideFrameworkElementGenerateEditingElement(DataGridCell cell,object dataItem){thrownewNotImplementedException("Should not be used.");}protectedoverrideFrameworkElementGenerateElement(DataGridCell cell,object dataItem){var control =newTextBox();
control.Style=(Style)Application.Current.TryFindResource("textBoxStyle");
control.FontSize=14;
control.VerticalContentAlignment=VerticalAlignment.Center;BindingOperations.SetBinding(control,TextBox.TextProperty,Binding);
control.IsReadOnly=IsReadOnly;return control;}}<DataGridGrid.Row="1" x:Name="exportData"Margin="15"VerticalAlignment="Stretch"ItemsSource="{Binding CSVExportData}"Style="{StaticResource dataGridStyle}"><DataGrid.Columns><local:DataGridTextBoxColumnHeader="Sample ID"Binding="{Binding SampleID}"IsReadOnly="True"></local:DataGridTextBoxColumn><local:DataGridTextBoxColumnHeader="Analysis Date"Binding="{Binding Date}"IsReadOnly="True"></local:DataGridTextBoxColumn><local:DataGridTextBoxColumnHeader="Test"Binding="{Binding Test}"IsReadOnly="True"></local:DataGridTextBoxColumn><local:DataGridTextBoxColumnHeader="Comment"Binding="{Binding Comment}"></local:DataGridTextBoxColumn></DataGrid.Columns></DataGrid>
Comme vous pouvez le voir, j'ai écrit mon propre DataGridTextColumn en héritant de tout ce qui est le DataGridBoundColumn. En remplaçant la méthode GenerateElement et en retournant un contrôle Textbox juste là, la méthode de génération de l'élément d'édition n'est jamais appelée. Dans un autre projet, j'ai utilisé ceci pour implémenter une colonne Datepicker, donc cela devrait également fonctionner pour les cases à cocher et les comboboxes.
Cela ne semble pas avoir d'impact sur le reste des comportements des datagrids. Au moins, je n'ai pas remarqué d'effets secondaires ni de commentaires négatifs jusqu'à présent.
Une solution simple si vous êtes d'accord que votre cellule reste une zone de texte (pas de distinction entre le mode édition et non-édition). De cette façon, l'édition en un seul clic fonctionne immédiatement. Cela fonctionne également avec d'autres éléments comme la liste déroulante et les boutons. Sinon, utilisez la solution ci-dessous la mise à jour.
J'ai essayé tout ce que j'ai trouvé ici et sur Google et j'ai même essayé de créer mes propres versions. Mais chaque réponse / solution fonctionnait principalement pour les colonnes de zone de texte mais ne fonctionnait pas avec tous les autres éléments (cases à cocher, comboboxes, colonnes de boutons), ou même cassait ces autres colonnes d'éléments ou avait d'autres effets secondaires. Merci Microsoft d'avoir fait en sorte que datagrid se comporte de cette manière moche et nous force à créer ces hacks. Pour cette raison, j'ai décidé de créer une version qui peut être appliquée avec un style à une colonne de zone de texte directement sans affecter les autres colonnes.
Caractéristiques
Aucun code derrière. Compatible MVVM.
Cela fonctionne lorsque vous cliquez sur différentes cellules de zone de texte dans les mêmes lignes ou sur des lignes différentes.
Ajoutez ce style. Le BasedOnest important lorsque vous utilisez des styles sophistiqués pour votre grille de données et que vous ne voulez pas les perdre.
Et maintenant, ajoutez cette classe au même espace de noms que votre MainViewModel (ou à un autre espace de noms. Mais vous devrez alors utiliser un autre préfixe d'espace de noms que local). Bienvenue dans le monde du code passe-partout laid des comportements attachés.
usingSystem.Windows;usingSystem.Windows.Controls;usingSystem.Windows.Media;namespaceYourMainViewModelNameSpace{publicstaticclassDataGridTextBoxSingleClickEditBehavior{publicstaticreadonlyDependencyPropertyEnableProperty=DependencyProperty.RegisterAttached("Enable",typeof(bool),typeof(DataGridTextBoxSingleClickEditBehavior),newFrameworkPropertyMetadata(false,OnEnableChanged));publicstaticboolGetEnable(FrameworkElement frameworkElement){return(bool) frameworkElement.GetValue(EnableProperty);}publicstaticvoidSetEnable(FrameworkElement frameworkElement,boolvalue){
frameworkElement.SetValue(EnableProperty,value);}privatestaticvoidOnEnableChanged(DependencyObject d,DependencyPropertyChangedEventArgs e){if(d isDataGridCell dataGridCell)
dataGridCell.PreviewMouseLeftButtonDown+=DataGridCell_PreviewMouseLeftButtonDown;}privatestaticvoidDataGridCell_PreviewMouseLeftButtonDown(object sender,System.Windows.Input.MouseButtonEventArgs e){EditCell(sender asDataGridCell, e);}privatestaticvoidEditCell(DataGridCell dataGridCell,RoutedEventArgs e){if(dataGridCell ==null|| dataGridCell.IsEditing|| dataGridCell.IsReadOnly)return;if(dataGridCell.IsFocused==false)
dataGridCell.Focus();var dataGrid =FindVisualParent<DataGrid>(dataGridCell);
dataGrid?.BeginEdit(e);}privatestatic T FindVisualParent<T>(UIElement element)where T :UIElement{var parent =VisualTreeHelper.GetParent(element)asUIElement;while(parent !=null){if(parent is T parentWithCorrectType)return parentWithCorrectType;
parent =VisualTreeHelper.GetParent(parent)asUIElement;}returnnull;}}}
Réponses:
Voici comment j'ai résolu ce problème:
Ce DataGrid est lié à un CollectionViewSource (contenant des objets Personne factice ).
La magie opère ici: DataGridCell.Selected = "DataGridCell_Selected" .
J'accroche simplement l'événement sélectionné de la cellule DataGrid et j'appelle BeginEdit () sur le DataGrid.
Voici le code derrière le gestionnaire d'événements:
la source
SelectionUnit
propriété sur le DataGrid surCell
.grd.BeginEdit(e)
, je veux que la zone de texte de cette cellule ait le focus. Comment puis je faire ça? J'ai essayé d'appelerFindName("txtBox")
à la fois le DataGridCell et le DataGrid, mais il renvoie null pour moi.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 était déjà en mode d'édition, j'ai dû l'ajuster un peu. Utiliser SelectionUnit Cell n'était pas une option pour moi.
Au lieu d'utiliser l'événement DataGridCell.Selected qui n'est déclenché que pour la première fois que l'utilisateur clique sur la cellule d'une ligne, j'ai utilisé l'événement DataGridCell.GotFocus.
Si vous le faites, 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 ceci
la source
De: http://wpf.codeplex.com/wikipage?title=Single-Click%20Editing
XAML:
CODE-DERRIÈRE:
la source
La solution de http://wpf.codeplex.com/wikipage?title=Single-Click%20Editing a très bien fonctionné pour moi, mais je l'ai activée pour chaque DataGrid en utilisant un style défini dans un ResourceDictionary. Pour utiliser des gestionnaires dans des dictionnaires de ressources, vous devez y ajouter un fichier code-behind. Voici comment procéder:
Ceci est un dictionnaire de ressources DataGridStyles.xaml :
Notez l'attribut x: Class dans l'élément racine. Créez un fichier de classe. Dans cet exemple, ce serait DataGridStyles.xaml.cs . Mettez ce code à l'intérieur:
la source
je préfère cette méthode basée sur la suggestion de Dušan Knežević. vous cliquez et c'est tout))
la source
Je l'ai résolu en ajoutant un déclencheur qui définit la propriété IsEditing de DataGridCell sur True lorsque la souris est dessus. Cela a résolu la plupart de mes problèmes. Cela fonctionne aussi avec les comboboxes.
la source
Je recherche une cellule d'édition en un seul clic dans MVVM et c'est une autre façon de le faire.
Ajout d'un comportement en xaml
La classe EditCellOnSingleClickBehavior étend System.Windows.Interactivity.Behavior;
Voila!
la source
Il y a deux problèmes avec la réponse de user2134678. L'un est très mineur et n'a aucun effet fonctionnel. L'autre est assez significatif.
Le premier problème est que le GotFocus est en fait appelé par rapport au DataGrid, et non au DataGridCell en 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é. Entrée devrait vous déplacer vers la cellule suivante sous la cellule actuelle dans un comportement DataGrid normal. Cependant, ce qui se passe réellement dans les coulisses, c'est que l'événement GotFocus sera appelé deux fois. Une fois sur la cellule actuelle perdant la focalisation, et une fois sur la nouvelle cellule gagnant la concentration. 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 modification en un clic, mais quiconque ne clique pas littéralement sur la grille sera incommodé, et un concepteur d'interface utilisateur ne doit pas supposer que tous les utilisateurs utilisent des souris. (Les utilisateurs de clavier peuvent en quelque sorte le contourner en utilisant Tab, mais cela signifie toujours qu'ils sautent à travers des cerceaux dont ils ne devraient pas avoir besoin.)
Alors, la solution à ce problème? Gérez l'événement KeyDown pour la cellule et si la clé est la clé Entrée, définissez un indicateur qui empêche BeginEdit de se déclencher sur la première cellule. Maintenant, la touche Entrée se comporte comme il se doit.
Pour commencer, ajoutez le style suivant à votre DataGrid:
Appliquez ce style à la propriété "CellStyle" des colonnes pour lesquelles vous souhaitez activer en un clic.
Ensuite, dans le code derrière 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):
Ensuite, vous ajoutez votre gestionnaire pour l'événement KeyDown:
Vous disposez maintenant d'un DataGrid qui n'a modifié aucun comportement fondamental de l'implémentation prête à l'emploi et qui prend en charge l'édition en un seul clic.
la source
Je sais que je suis un peu en retard à la fête mais j'ai eu le même problème et j'ai trouvé une solution différente:
Comme vous pouvez le voir, j'ai écrit mon propre DataGridTextColumn en héritant de tout ce qui est le DataGridBoundColumn. En remplaçant la méthode GenerateElement et en retournant un contrôle Textbox juste là, la méthode de génération de l'élément d'édition n'est jamais appelée. Dans un autre projet, j'ai utilisé ceci pour implémenter une colonne Datepicker, donc cela devrait également fonctionner pour les cases à cocher et les comboboxes.
Cela ne semble pas avoir d'impact sur le reste des comportements des datagrids. Au moins, je n'ai pas remarqué d'effets secondaires ni de commentaires négatifs jusqu'à présent.
la source
Mettre à jour
Une solution simple si vous êtes d'accord que votre cellule reste une zone de texte (pas de distinction entre le mode édition et non-édition). De cette façon, l'édition en un seul clic fonctionne immédiatement. Cela fonctionne également avec d'autres éléments comme la liste déroulante et les boutons. Sinon, utilisez la solution ci-dessous la mise à jour.
Fin de la mise à jour
Rant
J'ai essayé tout ce que j'ai trouvé ici et sur Google et j'ai même essayé de créer mes propres versions. Mais chaque réponse / solution fonctionnait principalement pour les colonnes de zone de texte mais ne fonctionnait pas avec tous les autres éléments (cases à cocher, comboboxes, colonnes de boutons), ou même cassait ces autres colonnes d'éléments ou avait d'autres effets secondaires. Merci Microsoft d'avoir fait en sorte que datagrid se comporte de cette manière moche et nous force à créer ces hacks. Pour cette raison, j'ai décidé de créer une version qui peut être appliquée avec un style à une colonne de zone de texte directement sans affecter les autres colonnes.
Caractéristiques
Sources
J'ai utilisé cette solution et la réponse de @ my et les ai modifiées pour qu'elles soient un comportement attaché. http://wpf-tutorial-net.blogspot.com/2016/05/wpf-datagrid-edit-cell-on-single-click.html
Comment l'utiliser
Ajoutez ce style. Le
BasedOn
est important lorsque vous utilisez des styles sophistiqués pour votre grille de données et que vous ne voulez pas les perdre.Appliquez le style avec
CellStyle
à chacun de vosDataGridTextColumns
comme ceci:Et maintenant, ajoutez cette classe au même espace de noms que votre MainViewModel (ou à un autre espace de noms. Mais vous devrez alors utiliser un autre préfixe d'espace de noms que
local
). Bienvenue dans le monde du code passe-partout laid des comportements attachés.la source
la source