¿Cómo se realiza la selección de la checkbox con un solo clic en WPF DataGrid?

Tengo un DataGrid con la primera columna como columna de texto y una segunda columna como columna CheckBox. Lo que quiero es que haga clic en la checkbox. Debería ser verificado.

Sin embargo, se necesitan dos clics para ser seleccionado, para el primer clic se selecciona la celda, para los segundos clics se marca la checkbox. Cómo hacer que la checkbox se marque / desmarque con un solo clic.

Estoy usando WPF 4.0. Las columnas en el DataGrid son Autogeneradas.

Para la checkbox DataGrid con un solo clic, puede poner el control de casilla regular dentro de DataGridTemplateColumn y establecer UpdateSourceTrigger=PropertyChanged .

      

Lo resolví con el siguiente Estilo:

   

Por supuesto, es posible adaptar esto aún más para columnas específicas …

En primer lugar, sé que esta es una pregunta bastante antigua, pero aún así pensé en intentar responderla.

Tuve el mismo problema hace un par de días y encontré una solución sorprendentemente corta (vea este blog ). Básicamente, todo lo que necesita hacer es reemplazar la definición de DataGridCheckBoxColumn en su XAML con lo siguiente:

        

La ventaja de esta solución es obvia: es solo XAML; por lo tanto, evita que cargue su código de retorno con lógica de UI adicional y lo ayuda a mantener su estado a los ojos de los fanáticos de MVVM;).

Basado en el blog al que se hace referencia en la respuesta de Goblin, pero modificado para trabajar en .NET 4.0 y con el modo de selección de filas.

Tenga en cuenta que también acelera la edición de DataGridComboBoxColumn, ingresando al modo de edición y mostrando el menú desplegable con un solo clic o entrada de texto.

XAML:

   

Código detrás:

  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(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(cell); if (row != null && !row.IsSelected) { row.IsSelected = true; } } } else { ComboBox cb = cell.Content as ComboBox; if (cb != null) { //DataGrid dataGrid = FindVisualParent(cell); dataGrid.BeginEdit(e); cell.Dispatcher.Invoke( DispatcherPriority.Background, new Action(delegate { })); cb.IsDropDownOpen = true; } } } private static T FindVisualParent(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; } 

Para que la respuesta de Konstantin Salavatov funcione con AutoGenerateColumns , agregue un controlador de eventos al AutoGeneratingColumn DataGrid con el siguiente código:

 if (e.Column is DataGridCheckBoxColumn && !e.Column.IsReadOnly) { var checkboxFactory = new FrameworkElementFactory(typeof(CheckBox)); checkboxFactory.SetValue(FrameworkElement.HorizontalAlignmentProperty, HorizontalAlignment.Center); checkboxFactory.SetValue(FrameworkElement.VerticalAlignmentProperty, VerticalAlignment.Center); checkboxFactory.SetBinding(ToggleButton.IsCheckedProperty, new Binding(e.PropertyName) { UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged }); e.Column = new DataGridTemplateColumn { Header = e.Column.Header, CellTemplate = new DataTemplate { VisualTree = checkboxFactory }, SortMemberPath = e.Column.SortMemberPath }; } 

Esto hará que todas las columnas de checkbox generadas automáticamente de DataGrid sean editables con “un solo clic”.

Intenté estas sugerencias, y muchas otras que encontré en otros sitios, pero ninguna de ellas me funcionó. Al final, creé la siguiente solución.

Creé mi propio control heredado de DataGrid y simplemente le agregué este código:

 public class DataGridWithNavigation : Microsoft.Windows.Controls.DataGrid { public DataGridWithNavigation() { EventManager.RegisterClassHandler(typeof(DataGridCell), DataGridCell.PreviewMouseLeftButtonDownEvent, new RoutedEventHandler(this.OnPreviewMouseLeftButtonDown)); } private void OnPreviewMouseLeftButtonDown(object sender, RoutedEventArgs e) { DataGridCell cell = sender as DataGridCell; if (cell != null && !cell.IsEditing && !cell.IsReadOnly) { DependencyObject obj = FindFirstControlInChildren(cell, "CheckBox"); if (obj != null) { System.Windows.Controls.CheckBox cb = (System.Windows.Controls.CheckBox)obj; cb.Focus(); cb.IsChecked = !cb.IsChecked; } } } public DependencyObject FindFirstControlInChildren(DependencyObject obj, string controlType) { if (obj == null) return null; // Get a list of all occurrences of a particular type of control (eg "CheckBox") IEnumerable ctrls = FindInVisualTreeDown(obj, controlType); if (ctrls.Count() == 0) return null; return ctrls.First(); } public IEnumerable FindInVisualTreeDown(DependencyObject obj, string type) { if (obj != null) { if (obj.GetType().ToString().EndsWith(type)) { yield return obj; } for (var i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) { foreach (var child in FindInVisualTreeDown(VisualTreeHelper.GetChild(obj, i), type)) { if (child != null) { yield return child; } } } } yield break; } } 

¿Qué hace todo esto?

Bueno, cada vez que hacemos clic en cualquier celda de nuestro DataGrid, vemos si la celda contiene un control CheckBox dentro de ella. Si lo hace , entonces estableceremos el foco en ese CheckBox y alternar su valor .

Esto parece funcionar para mí, y es una solución agradable, fácilmente reutilizable.

Sin embargo, es decepcionante que necesitemos escribir un código para hacer esto. La explicación de que el primer clic del mouse (en un CheckGox de DataGrid) se "ignora" como WPF lo usa para poner la fila en el modo de edición puede sonar lógico, pero en el mundo real, va en contra de la forma en que funciona cada aplicación real.

Si un usuario ve una checkbox en su pantalla, debería poder hacer clic una vez para marcarla / desmarcarla. Fin de la historia.

Aquí hay una solución mucho más simple.

           

Si usa DataGridCheckBoxColumn para implementar, primero haga clic en enfocar, segundo clic en verificar.

Pero el uso de DataGridTemplateColumn para implementar necesita un solo clic.

La diferencia de usar DataGridComboboxBoxColumn y la implementación de DataGridTemplateColumn también es similar.

Lo resolví con esto:

          

La checkbox activa en un solo clic!

Basado en la respuesta de Jim Adorno y comentarios en su publicación, esta es una solución con MultiTrigger :

   

Otra solución simple es agregar este estilo a su DataGridColumn. El cuerpo de su estilo puede estar vacío.

      
   
 Imports System.Globalization Public Class CheckBoxColumnToEditingConvertor Implements IValueConverter Public Function Convert(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As CultureInfo) As Object Implements IValueConverter.Convert Try Return TypeOf TryCast(value, DataGridCell).Column Is DataGridCheckBoxColumn Catch ex As Exception Return Visibility.Collapsed End Try End Function Public Function ConvertBack(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As CultureInfo) As Object Implements IValueConverter.ConvertBack Throw New NotImplementedException() End Function End Class