How to perform Single click checkbox selection in WPF DataGrid?

匿名 (未验证) 提交于 2019-12-03 01:49:02

问题:

I have a DataGrid with first column as text column and second column as CheckBox column. What I want is, if I click the check box. It should get checked.

But, it takes two click to get selected, for first click the cell is getting selected, for the second clicks the check box is getting checked. How to make the check box to get checked/unchecked with a single click.

I'm using WPF 4.0. Columns in the DataGrid are AutoGenerated.

回答1:

For single click DataGrid checkbox you can just put regular checkbox control inside DataGridTemplateColumn and set UpdateSourceTrigger=PropertyChanged.



回答2:

I solved this with the following Style:

It's of course possible to adapt this further for specific columns ...



回答3:

Based on blog referenced in Goblin's answer, but modified to work in .NET 4.0 and with Row-Selection Mode.

Notice that it also speeds up DataGridComboBoxColumn editing - by entering edit mode and displaying dropdown on single click or text input.

XAML:

        

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


回答4:

First of, I know this is a pretty old question but I still thought I'd try and answer it.

I had the same problem a couple of days ago and came across a surprisingly short solution for it (see this blog). Basically, all you need to do is replace the DataGridCheckBoxColumn definition in your XAML with the following:

The upside of this solution is obvious - it's XAML-only; thus it effectively refrains your from burdening your code-back with additional UI logic and helps you maintain your status in the eyes of MVVM zealots ;).



回答5:

To make Konstantin Salavatov's answer work with AutoGenerateColumns, add an event handler to the DataGrid's AutoGeneratingColumn with the following code:

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

This will make all of DataGrid's auto-generated checkbox columns be "single click" editable.



回答6:

I've tried these suggestions, and plenty of others I've found on other sites, but none of them quite worked for me. In the end, I created the following solution.

I've created my own DataGrid-inherited control, and simply added this code to it:

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 

What does all this do ?

Well, each time we click on any cell in our DataGrid, we see if the cell contains a CheckBox control within it. If it does, then we'll set the focus to that CheckBox and toggle it's value.

This seems to work for me, and is a nice, easily reusable solution.

It is disappointing that we need to write code to do this though. The explanation that the first mouse click (on a DataGrid's CheckBox) is "ignored" as WPF uses it to put the row into Edit mode might sound logical, but in the real-world, this goes against the way every real application works.

If a user sees a checkbox on their screen, they should be able to click on it once to tick/untick it. End of story.



回答7:

There is a much simpler solution here.

          

If you use DataGridCheckBoxColumn to implement, first click is to focus, second click is to check.

But using DataGridTemplateColumn to implement needs one click only.

The difference of using DataGridComboboxBoxColumn and implementation by DataGridTemplateColumn is also similar.



回答8:

I solved with this:

The checkbox active on single click!



回答9:

Base on Jim Adorno answer and comments on his post, this is solution with MultiTrigger:



回答10:

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 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!