У меня есть DataGrid с первым столбцом в качестве текстового столбца и вторым столбцом в качестве столбца CheckBox. Я хочу, чтобы я установил флажок. Это нужно проверить.
Но для выбора требуется два щелчка, при первом щелчке выбирается ячейка, при втором щелчке устанавливается флажок. Как сделать так, чтобы флажок ставился / снимался одним щелчком мыши.
Я использую WPF 4.0. Столбцы в DataGrid создаются автоматически.
wpf
datagrid
wpfdatagrid
Принц Ашитака
источник
источник
Ответы:
Для флажка DataGrid одним щелчком вы можете просто поместить внутрь обычный флажок
DataGridTemplateColumn
и установить егоUpdateSourceTrigger=PropertyChanged
.<DataGridTemplateColumn.CellTemplate> <DataTemplate> <CheckBox IsChecked="{Binding Path=IsSelected, UpdateSourceTrigger=PropertyChanged}" /> </DataTemplate> </DataGridTemplateColumn.CellTemplate>
источник
DataGridTemplateColumn.CellTemplate
с вашей собственной Binding и он будет работать !! Ответ @ weidian-huang помог мне понять это, спасибо!Я решил это с помощью следующего стиля:
<Style TargetType="DataGridCell"> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="IsEditing" Value="True" /> </Trigger> </Style.Triggers> </Style>
Конечно, это можно адаптировать для конкретных столбцов ...
источник
Во-первых, я знаю, что это довольно старый вопрос, но я все же подумал, что попробую ответить на него.
У меня была такая же проблема пару дней назад, и я нашел удивительно короткое решение для нее (см. Этот блог ). По сути, все, что вам нужно сделать, это заменить
DataGridCheckBoxColumn
определение в вашем XAML следующим:<DataGridTemplateColumn Header="MyCheckBoxColumnHeader"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <CheckBox HorizontalAlignment="Center" VerticalAlignment="Center" IsChecked="{Binding Path=MyViewModelProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn>
Положительные стороны этого решения очевидны - оно работает только с XAML; таким образом, он эффективно удерживает вас от обременения вашего кода дополнительной логикой пользовательского интерфейса и помогает вам поддерживать свой статус в глазах фанатиков MVVM;).
источник
Чтобы ответ Константина Салаватова работал
AutoGenerateColumns
, добавьте обработчик события вDataGrid
'sAutoGeneratingColumn
со следующим кодом: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
автоматически сгенерированные столбцы флажков доступными для редактирования "одним щелчком".источник
На основе блога, упомянутого в ответе Гоблина, но измененного для работы в .NET 4.0 и с режимом выбора строк.
Обратите внимание, что это также ускоряет редактирование DataGridComboBoxColumn - за счет перехода в режим редактирования и отображения раскрывающегося списка при однократном щелчке или вводе текста.
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; }
источник
Я пробовал эти предложения и множество других, которые нашел на других сайтах, но ни один из них не помог мне. В итоге я создал следующее решение.
Я создал свой собственный элемент управления, унаследованный от DataGrid, и просто добавил к нему этот код:
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 и переключим его значение. .
Мне кажется, это работает, и это хорошее решение, которое легко использовать повторно.
Жаль, что нам нужно написать код. Объяснение того, что первый щелчок мышью (на CheckBox DataGrid) «игнорируется», поскольку WPF использует его для перевода строки в режим редактирования, может показаться логичным, но в реальном мире это идет вразрез с тем, как работает каждое реальное приложение.
Если пользователь видит на своем экране флажок, он должен иметь возможность щелкнуть по нему один раз, чтобы установить / снять флажок. Конец истории.
источник
Здесь есть гораздо более простое решение.
<DataGridTemplateColumn MinWidth="20" > <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Grid> <CheckBox VerticalAlignment="Center" HorizontalAlignment="Center"/> </Grid> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn>
Если вы используете
DataGridCheckBoxColumn
для реализации, первый щелчок - это фокусировка, второй - проверка.Но
DataGridTemplateColumn
для использования достаточно одного щелчка мышки.Аналогичная разница в использовании
DataGridComboboxBoxColumn
и реализацииDataGridTemplateColumn
.источник
Я решил с этим:
<DataGridTemplateColumn> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Viewbox Height="25"> <CheckBox IsChecked="{Binding TheProperty, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/> </Viewbox> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn>
Флажок активируется одним щелчком мыши!
источник
Основываясь на ответе Джима Адорно и комментариях к его сообщению, это решение с
MultiTrigger
:<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>
источник
Еще одно простое решение - добавить этот стиль в ваш DataGridColumn. Тело вашего стиля может быть пустым.
<DataGridCheckBoxColumn> <DataGridCheckBoxColumn.ElementStyle> <Style TargetType="CheckBox"> </Style> </DataGridCheckBoxColumn.ElementStyle> </DataGridCheckBoxColumn>
источник
<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
источник