如何在WPF DataGrid中单击checkboxselect?
我有一个DataGrid第一列作为文本列和第二列作为CheckBox列。 我想要的是,如果我点击checkbox。 它应该得到检查。
但是,需要两次点击才能被选中,首先点击单元格被选中,第二次点击checkbox被选中。 如何使checkbox得到检查/取消选中一次点击。
注意:我正在使用WPF 4.0
编辑: DataGrid中的列是自动生成的。
这是3.5sp1,我知道 – 但它应该在4.0下工作: Vinsibal 。
对于单击数据网格checkbox,您可以将常规checkbox控件放在DataGridTemplateColumn中,并设置UpdateSourceTrigger = PropertyChanged即可。 很简单。 🙂
<DataGridTemplateColumn.CellTemplate> <DataTemplate> <CheckBox IsChecked="{Binding Path=IsSelected, UpdateSourceTrigger=PropertyChanged}" /> </DataTemplate> </DataGridTemplateColumn.CellTemplate>
我用下面的样式解决了这个问题:
<Style TargetType="DataGridCell"> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="IsEditing" Value="True" /> </Trigger> </Style.Triggers> </Style>
这当然可以进一步适应特定的列…
根据Goblin的答案引用的博客,但修改后的工作在.NET 4.0和行select模式。
注意,它也加快了DataGridComboBoxColumn编辑的速度 – 通过进入编辑模式并显示下拉单击或文本input。
XAML:
<Style TargetType="{x:Type DataGridCell}"> <EventSetter Event="PreviewMouseLeftButtonDown" Handler="DataGridCell_PreviewMouseLeftButtonDown" /> <EventSetter Event="PreviewTextInput" Handler="DataGridCell_PreviewTextInput" /> </Style>
代码隐藏:
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<DataGrid>(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<DataGridRow>(cell); if (row != null && !row.IsSelected) { row.IsSelected = true; } } } else { ComboBox cb = cell.Content as ComboBox; if (cb != null) { //DataGrid dataGrid = FindVisualParent<DataGrid>(cell); dataGrid.BeginEdit(e); cell.Dispatcher.Invoke( DispatcherPriority.Background, new Action(delegate { })); cb.IsDropDownOpen = true; } } } private 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; }
首先,我知道这是一个相当古老的问题,但我仍然认为我会试着回答。
几天前,我遇到了同样的问题,并遇到了一个令人惊讶的短期解决scheme(请参阅此博客 )。 基本上,你所要做的就是用下面的代码replace你的XAML中的DataGridCheckBoxColumn
定义:
<DataGridTemplateColumn Header="MyCheckBoxColumnHeader"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <CheckBox HorizontalAlignment="Center" VerticalAlignment="Center" IsChecked="{Binding Path=MyViewModelProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn>
这个解决scheme的好处是显而易见的 – 它只是XAML; 因此它有效地避免了用额外的UI逻辑加重代码的负担,并有助于保持你在MVVM狂热者眼中的地位;)。
要使Konstantin Salavatov的答案适用于AutoGenerateColumns
,请使用以下代码向DataGrid
的AutoGeneratingColumn
添加事件处理程序:
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 }; }
这将使DataGrid
的所有自动生成的checkbox列都是“单击”可编辑的。
我已经尝试了这些build议,以及其他网站上发现的其他许多人,但是他们中没有人为我工作。 最后,我创build了以下解决scheme。
我创build了我自己的DataGridinheritance的控件,并简单地将此代码添加到它:
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<DependencyObject> ctrls = FindInVisualTreeDown(obj, controlType); if (ctrls.Count() == 0) return null; return ctrls.First(); } public IEnumerable<DependencyObject> 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; } }
这一切做什么?
那么,每当我们点击DataGrid中的任何单元格,就会看到单元格是否包含CheckBox控件。 如果是这样 ,那么我们将把焦点设置到该CheckBox 并切换它的值 。
这似乎为我工作,是一个很好,很容易重用的解决scheme。
我们需要编写代码来做到这一点令人失望。 第一次鼠标点击(在DataGrid的CheckBox上)被“忽略”的解释是因为WPF使用它来将该行置于Edit模式可能听起来合乎逻辑,但是在现实世界中,这与每个实际应用程序的工作方式背道而驰。
如果用户在他们的屏幕上看到一个checkbox,他们应该能够点击一次来勾选/取消选中。 故事结局。
这里有一个更简单的解决scheme。
<DataGridTemplateColumn MinWidth="20" > <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Grid> <CheckBox VerticalAlignment="Center" HorizontalAlignment="Center"/> </Grid> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn>
如果你使用DataGridCheckBoxColumn
来实现,首先点击是要重点,第二点是检查。
但是使用DataGridTemplateColumn
来实现只需要一次点击。
使用DataGridComboboxBoxColumn
和DataGridComboboxBoxColumn
实现的区别也是相似的。
根据Jim Adorno的回复和对他的post的评论,这是MultiTrigger
解决scheme:
<Style TargetType="DataGridCell"> <Style.Triggers> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsReadOnly" Value="False" /> <Condition Property="IsMouseOver" Value="True" /> </MultiTrigger.Conditions> <Setter Property="IsEditing" Value="True" /> </MultiTrigger> </Style.Triggers> </Style>
我解决了这个问题:
<DataGridTemplateColumn> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Viewbox Height="25"> <CheckBox IsChecked="{Binding TheProperty, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/> </Viewbox> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn>
checkbox激活单击!
<Style x:Key="StilCelula" TargetType="DataGridCell"> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="IsEditing" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Converter={StaticResource CheckBoxColumnToEditingConvertor}}" /> </Trigger> </Style.Triggers> <Style>
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