Quiero que el usuario pueda poner la celda en modo de edición y resaltar la fila en la que está contenida la celda con un solo clic. Por defecto, esto es doble clic.
Este DataGrid está vinculado a CollectionViewSource (que contiene objetos Person ficticios ).
La magia sucede allí: DataGridCell.Selected = "DataGridCell_Selected" .
Simplemente engancho el evento seleccionado de la celda DataGrid y llamo a BeginEdit () en el DataGrid.
Aquí está el código subyacente para el controlador de eventos:
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);}}
Puede solucionar el problema de la fila ya seleccionada estableciendo la SelectionUnitpropiedad en DataGrid en Cell.
Matt Winckler
Supongamos que tengo un TextBox en mi DataGridCell. Después de llamar grd.BeginEdit(e), quiero que el TextBox en esa celda tenga el foco. ¿Cómo puedo hacer eso? Intenté llamar FindName("txtBox")tanto a DataGridCell como a DataGrid, pero me devuelve nulo.
user1214135
GotFocus = "DataGrid_GotFocus" parece faltar?
sinérgico
4
Esto funciona bien, pero no recomendaría hacerlo. He usado esto en mi proyecto y decidí retroceder al comportamiento estándar de DG. En el futuro, cuando su DG crezca y se vuelva complejo, tendrá problemas de validación, agregar nuevas filas y otros comportamientos extraños.
white.zaz
1
¿@ white.zaz estaba contento con el cliente después de que hiciste la reversión al comportamiento estándar de DG? Porque la razón principal por la que se hizo esta pregunta fue que la edición en las capacidades estándar de DG no es fácil de usar, ya que necesita hacer clic demasiadas veces antes de que DG entre en el modo de edición.
AEMLoviji
42
La respuesta de Micael Bergeron fue un buen comienzo para encontrar una solución que me funcione. Para permitir la edición con un solo clic también para las celdas en la misma fila que ya está en modo de edición, tuve que ajustarlo un poco. Usar SelectionUnit Cell no fue una opción para mí.
En lugar de usar el evento DataGridCell.Selected, que solo se activa por primera vez, se hace clic en la celda de una fila, utilicé el evento DataGridCell.GotFocus.
Si lo hace, siempre tendrá la celda correcta enfocada y en modo de edición, pero no se enfocará ningún control en la celda, esto lo resolví así
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;}
esto no funciona en ciertos casos, y es más complicada que la solución de Micael Bergerons.
SwissCoder
Para mí, esta casi fue la solución. Necesitaba agregar un controlador de eventos "PreviewMouseLeftButtonUp" y poner allí exactamente el mismo código.
Néstor Sánchez A.
esto tampoco funciona una vez que tienes un cuadro combinado. el clic de vista previa ve clics en la ventana emergente del cuadro combinado, luego la llamada cell.focus arruina todo. La solución más fácil es agregar una sección que observe la fuente original de los eventos del mouse, usando FindVisualParent en eso para ver si está dentro de la cuadrícula de datos. si no, no hagas ningún otro trabajo.
John Gardner
7
La solución de http://wpf.codeplex.com/wikipage?title=Single-Click%20Editing funcionó muy bien para mí, pero la habilité para cada DataGrid usando un estilo definido en un ResourceDictionary. Para utilizar controladores en los diccionarios de recursos, debe agregarle un archivo de código subyacente. Así es como lo haces:
Este es un diccionario de recursos 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>
Tenga en cuenta el atributo x: Class en el elemento raíz. Crea un archivo de clase. En este ejemplo, sería DataGridStyles.xaml.cs . Pon este código dentro:
usingSystem.Windows.Controls;usingSystem.Windows;usingSystem.Windows.Input;namespaceYourNamespace{partialclassDataGridStyles:ResourceDictionary{publicDataGridStyles(){InitializeComponent();}// The code from the myermian's answer goes here.}
Esto no funciona si se usa un cuadro combinado como plantilla de edición, supongo que otras como la casilla de verificación que captura los eventos del mouse también se romperían
Steve
Para mí, esto funciona con columnas de cuadro combinado, pero el cuadro de texto de la "nueva línea de elemento" (última línea) tiene un comportamiento extraño: al primer clic obtengo el foco de entrada y puedo escribir cosas. Cuando muevo el mouse fuera de la celda , el valor del cuadro de texto desaparece. Al escribir más, el texto recién ingresado se guarda correctamente (crea una nueva entrada como se desea). Esto también ocurre incluso con un ComboboxColumn.
FrankM
Inicialmente parece que funciona bien, pero arruinó totalmente mi Datagrid, cuando trato de ordenar, todos estos valores desaparecen, sin este código, todo funciona bien con la ordenación.
Chandraprakash
3
Lo resolví agregando un disparador que establece la propiedad IsEditing de DataGridCell en True cuando el mouse está sobre él. Resolvió la mayoría de mis problemas. También funciona con cuadros combinados.
No funciona ... pierde la edición tan pronto como el mouse sale de la celda. Entonces, 1) haga clic con el botón izquierdo en la celda que desea editar. 2) mueva el mouse fuera del camino 3) Empiece a escribir. Su escritura no funciona porque la celda ya no está en modo de edición.
Skarsnik
1
tampoco funciona para mí. me impide editar el cuadro de texto
Blechdose
Pero hay un problema con este enfoque, había bloqueado la primera columna para editar, con este enfoque, ¡esto hace que la primera columna también sea editable!
Chandraprakash
3
Estoy buscando editar la celda con un solo clic en MVVM y esta es otra forma de hacerlo.
Hay dos problemas con la respuesta de user2134678. Uno es muy pequeño y no tiene ningún efecto funcional. El otro es bastante significativo.
El primer problema es que GotFocus en realidad se llama contra DataGrid, no contra DataGridCell en la práctica. El calificador DataGridCell en XAML es redundante.
El principal problema que encontré con la respuesta es que el comportamiento de la tecla Enter está roto. Enter debería moverlo a la siguiente celda debajo de la celda actual en el comportamiento normal de DataGrid. Sin embargo, lo que realmente sucede detrás de escena es que el evento GotFocus se llamará dos veces. Una vez que la celda actual pierde el enfoque, y una vez que la nueva celda gana el foco. Pero mientras se llame a BeginEdit en esa primera celda, la siguiente celda nunca se activará. El resultado es que tiene la edición con un solo clic, pero cualquiera que no esté literalmente haciendo clic en la cuadrícula tendrá inconvenientes, y un diseñador de interfaz de usuario no debe asumir que todos los usuarios están usando ratones. (Los usuarios de teclado pueden sortearlo usando Tab, pero eso aún significa que están saltando obstáculos que no deberían necesitar).
Entonces, ¿la solución a este problema? Maneje el evento KeyDown para la celda y si la clave es la tecla Enter, establezca un indicador que impida que BeginEdit se active en la primera celda. Ahora la tecla Enter se comporta como debería.
Para empezar, agregue el siguiente estilo a su DataGrid:
Aplique ese estilo a la propiedad "CellStyle" de las columnas para las que desea habilitar un clic.
Luego, en el código detrás, tiene lo siguiente en su controlador GotFocus (tenga en cuenta que estoy usando VB aquí porque eso es lo que nuestro cliente de "solicitud de cuadrícula de datos con un solo clic" quería como lenguaje de desarrollo):
Luego agrega su controlador para el evento KeyDown:
PrivateSubDataGridCell_KeyDown(ByVal sender AsObject,ByVal e AsKeyEventArgs)If e.Key=Key.EnterThenMe._endEditing =TrueEndIfEndSub
Ahora tiene un DataGrid que no ha cambiado ningún comportamiento fundamental de la implementación lista para usar y, sin embargo, admite la edición con un solo clic.
Sé que llegué un poco tarde a la fiesta, pero tuve el mismo problema y se me ocurrió una solución diferente:
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>
Como puede ver, escribí mi propia DataGridTextColumn heredando todo lo relacionado con DataGridBoundColumn. Al anular el método GenerateElement y devolver un control Textbox allí mismo, nunca se llama al método para generar el elemento de edición. En un proyecto diferente, utilicé esto para implementar una columna Datepicker, por lo que también debería funcionar para casillas de verificación y cuadros combinados.
Esto no parece afectar el comportamiento del resto de las cuadrículas de datos. Al menos no he notado ningún efecto secundario ni he recibido comentarios negativos hasta ahora.
Una solución simple si está de acuerdo con que su celda siga siendo un cuadro de texto (sin distinguir entre el modo de edición y el de no editar). De esta manera, la edición con un solo clic funciona de inmediato. Esto también funciona con otros elementos como cuadro combinado y botones. De lo contrario, use la solución debajo de la actualización.
Probé todo lo que encontré aquí y en Google e incluso intenté crear mis propias versiones. Pero cada respuesta / solución funcionó principalmente para columnas de cuadro de texto, pero no funcionó con todos los demás elementos (casillas de verificación, cuadros combinados, columnas de botones), o incluso rompió esas otras columnas de elementos o tuvo algunos otros efectos secundarios. Gracias microsoft por hacer que datagrid se comporte de esa manera tan fea y nos obligue a crear esos trucos. Por eso, decidí hacer una versión que se pueda aplicar con un estilo a una columna de cuadro de texto directamente sin afectar a otras columnas.
Caracteristicas
Sin código detrás. Compatible con MVVM.
Funciona al hacer clic en diferentes celdas de cuadro de texto en la misma fila o en filas diferentes.
Y ahora agregue esta clase al mismo espacio de nombres que su MainViewModel (o un espacio de nombres diferente. Pero luego deberá usar un prefijo de espacio de nombres diferente local). Bienvenido al feo mundo de códigos repetitivos de comportamientos adjuntos.
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;}}}
Respuestas:
Así es como resolví este problema:
Este DataGrid está vinculado a CollectionViewSource (que contiene objetos Person ficticios ).
La magia sucede allí: DataGridCell.Selected = "DataGridCell_Selected" .
Simplemente engancho el evento seleccionado de la celda DataGrid y llamo a BeginEdit () en el DataGrid.
Aquí está el código subyacente para el controlador de eventos:
fuente
SelectionUnit
propiedad en DataGrid enCell
.grd.BeginEdit(e)
, quiero que el TextBox en esa celda tenga el foco. ¿Cómo puedo hacer eso? Intenté llamarFindName("txtBox")
tanto a DataGridCell como a DataGrid, pero me devuelve nulo.La respuesta de Micael Bergeron fue un buen comienzo para encontrar una solución que me funcione. Para permitir la edición con un solo clic también para las celdas en la misma fila que ya está en modo de edición, tuve que ajustarlo un poco. Usar SelectionUnit Cell no fue una opción para mí.
En lugar de usar el evento DataGridCell.Selected, que solo se activa por primera vez, se hace clic en la celda de una fila, utilicé el evento DataGridCell.GotFocus.
Si lo hace, siempre tendrá la celda correcta enfocada y en modo de edición, pero no se enfocará ningún control en la celda, esto lo resolví así
fuente
De: http://wpf.codeplex.com/wikipage?title=Single-Click%20Editing
XAML:
CÓDIGO DETRÁS:
fuente
La solución de http://wpf.codeplex.com/wikipage?title=Single-Click%20Editing funcionó muy bien para mí, pero la habilité para cada DataGrid usando un estilo definido en un ResourceDictionary. Para utilizar controladores en los diccionarios de recursos, debe agregarle un archivo de código subyacente. Así es como lo haces:
Este es un diccionario de recursos DataGridStyles.xaml :
Tenga en cuenta el atributo x: Class en el elemento raíz. Crea un archivo de clase. En este ejemplo, sería DataGridStyles.xaml.cs . Pon este código dentro:
fuente
Prefiero esta forma según la sugerencia de Dušan Knežević. haces clic en y eso es todo))
fuente
Lo resolví agregando un disparador que establece la propiedad IsEditing de DataGridCell en True cuando el mouse está sobre él. Resolvió la mayoría de mis problemas. También funciona con cuadros combinados.
fuente
Estoy buscando editar la celda con un solo clic en MVVM y esta es otra forma de hacerlo.
Agregar comportamiento en xaml
La clase EditCellOnSingleClickBehavior extiende System.Windows.Interactivity.Behavior;
¡Voila!
fuente
Hay dos problemas con la respuesta de user2134678. Uno es muy pequeño y no tiene ningún efecto funcional. El otro es bastante significativo.
El primer problema es que GotFocus en realidad se llama contra DataGrid, no contra DataGridCell en la práctica. El calificador DataGridCell en XAML es redundante.
El principal problema que encontré con la respuesta es que el comportamiento de la tecla Enter está roto. Enter debería moverlo a la siguiente celda debajo de la celda actual en el comportamiento normal de DataGrid. Sin embargo, lo que realmente sucede detrás de escena es que el evento GotFocus se llamará dos veces. Una vez que la celda actual pierde el enfoque, y una vez que la nueva celda gana el foco. Pero mientras se llame a BeginEdit en esa primera celda, la siguiente celda nunca se activará. El resultado es que tiene la edición con un solo clic, pero cualquiera que no esté literalmente haciendo clic en la cuadrícula tendrá inconvenientes, y un diseñador de interfaz de usuario no debe asumir que todos los usuarios están usando ratones. (Los usuarios de teclado pueden sortearlo usando Tab, pero eso aún significa que están saltando obstáculos que no deberían necesitar).
Entonces, ¿la solución a este problema? Maneje el evento KeyDown para la celda y si la clave es la tecla Enter, establezca un indicador que impida que BeginEdit se active en la primera celda. Ahora la tecla Enter se comporta como debería.
Para empezar, agregue el siguiente estilo a su DataGrid:
Aplique ese estilo a la propiedad "CellStyle" de las columnas para las que desea habilitar un clic.
Luego, en el código detrás, tiene lo siguiente en su controlador GotFocus (tenga en cuenta que estoy usando VB aquí porque eso es lo que nuestro cliente de "solicitud de cuadrícula de datos con un solo clic" quería como lenguaje de desarrollo):
Luego agrega su controlador para el evento KeyDown:
Ahora tiene un DataGrid que no ha cambiado ningún comportamiento fundamental de la implementación lista para usar y, sin embargo, admite la edición con un solo clic.
fuente
Sé que llegué un poco tarde a la fiesta, pero tuve el mismo problema y se me ocurrió una solución diferente:
Como puede ver, escribí mi propia DataGridTextColumn heredando todo lo relacionado con DataGridBoundColumn. Al anular el método GenerateElement y devolver un control Textbox allí mismo, nunca se llama al método para generar el elemento de edición. En un proyecto diferente, utilicé esto para implementar una columna Datepicker, por lo que también debería funcionar para casillas de verificación y cuadros combinados.
Esto no parece afectar el comportamiento del resto de las cuadrículas de datos. Al menos no he notado ningún efecto secundario ni he recibido comentarios negativos hasta ahora.
fuente
Actualizar
Una solución simple si está de acuerdo con que su celda siga siendo un cuadro de texto (sin distinguir entre el modo de edición y el de no editar). De esta manera, la edición con un solo clic funciona de inmediato. Esto también funciona con otros elementos como cuadro combinado y botones. De lo contrario, use la solución debajo de la actualización.
Fin de la actualización
Despotricar
Probé todo lo que encontré aquí y en Google e incluso intenté crear mis propias versiones. Pero cada respuesta / solución funcionó principalmente para columnas de cuadro de texto, pero no funcionó con todos los demás elementos (casillas de verificación, cuadros combinados, columnas de botones), o incluso rompió esas otras columnas de elementos o tuvo algunos otros efectos secundarios. Gracias microsoft por hacer que datagrid se comporte de esa manera tan fea y nos obligue a crear esos trucos. Por eso, decidí hacer una versión que se pueda aplicar con un estilo a una columna de cuadro de texto directamente sin afectar a otras columnas.
Caracteristicas
Fuentes
Usé esta solución y la respuesta de @ my y las modifiqué para que fueran un comportamiento adjunto. http://wpf-tutorial-net.blogspot.com/2016/05/wpf-datagrid-edit-cell-on-single-click.html
Cómo usarlo
Agrega este estilo. El
BasedOn
es importante cuando se utiliza algunos estilos de lujo para su cuadrícula de datos y usted no desea perder.Aplica el estilo con
CellStyle
a cada uno de tusDataGridTextColumns
así:Y ahora agregue esta clase al mismo espacio de nombres que su MainViewModel (o un espacio de nombres diferente. Pero luego deberá usar un prefijo de espacio de nombres diferente
local
). Bienvenido al feo mundo de códigos repetitivos de comportamientos adjuntos.fuente
fuente