如何在 WPF DataGrid 中执行单击复选框选择?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3833536/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to perform Single click checkbox selection in WPF DataGrid?
提问by Prince Ashitaka
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.
我有一个 DataGrid,第一列作为文本列,第二列作为 CheckBox 列。我想要的是,如果我单击复选框。它应该被检查。
但是,需要单击两次才能被选中,第一次单击单元格被选中,第二次单击复选框被选中。如何通过单击使复选框被选中/取消选中。
I'm using WPF 4.0. Columns in the DataGrid are AutoGenerated.
我正在使用 WPF 4.0。DataGrid 中的列是自动生成的。
回答by Konstantin Salavatov
For single click DataGrid checkbox you can just put regular checkbox control inside DataGridTemplateColumn
and set UpdateSourceTrigger=PropertyChanged
.
对于单击 DataGrid 复选框,您只需将常规复选框控件放入其中DataGridTemplateColumn
并设置UpdateSourceTrigger=PropertyChanged
.
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=IsSelected, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
回答by Jim Adorno
I solved this with the following Style:
我用以下样式解决了这个问题:
<Style TargetType="DataGridCell">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="IsEditing" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
It's of course possible to adapt this further for specific columns ...
当然可以针对特定的列进一步调整...
回答by Priidu Neemre
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:
几天前我遇到了同样的问题,并遇到了一个令人惊讶的简短解决方案(请参阅此博客)。基本上,您需要做的就是用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>
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 ;).
该解决方案的优点是显而易见的——它仅支持 XAML;因此,它可以有效地避免您用额外的 UI 逻辑来负担您的代码返回,并帮助您在 MVVM 狂热者眼中保持您的状态;)。
回答by Allon Guralnek
To make Konstantin Salavatov's answerwork with AutoGenerateColumns
, add an event handler to the DataGrid
's AutoGeneratingColumn
with the following code:
要使Konstantin Salavatov 的答案适用于AutoGenerateColumns
,请使用以下代码向DataGrid
's添加事件处理程序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
};
}
This will make all of DataGrid
's auto-generated checkbox columns be "single click" editable.
这将使所有DataGrid
自动生成的复选框列都可以“单击”编辑。
回答by surfen
Based on blog referenced in Goblin's answer, but modified to work in .NET 4.0 and with Row-Selection Mode.
基于 Goblin's answer 中引用的博客,但修改为在 .NET 4.0 和行选择模式下工作。
Notice that it also speeds up DataGridComboBoxColumn editing - by entering edit mode and displaying dropdown on single click or text input.
请注意,它还可以加快 DataGridComboBoxColumn 的编辑速度 - 通过进入编辑模式并在单击或文本输入时显示下拉列表。
XAML:
XAML:
<Style TargetType="{x:Type DataGridCell}">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="DataGridCell_PreviewMouseLeftButtonDown" />
<EventSetter Event="PreviewTextInput" Handler="DataGridCell_PreviewTextInput" />
</Style>
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<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;
}
回答by Mike Gledhill
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:
我已经创建了自己的继承自 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;
}
}
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.
好吧,每次我们单击 DataGrid 中的任何单元格时,我们都会查看该单元格中是否包含 CheckBox 控件。如果是,那么我们将焦点设置到那个 CheckBox并切换它的值。
This seems to work for me, and is a nice, easily reusable solution.
这似乎对我有用,并且是一个不错的、易于重用的解决方案。
It is disappointing that we needto 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.
令人失望的是,我们需要编写代码来做到这一点。第一次鼠标点击(在 DataGrid 的 CheckBox 上)被“忽略”的解释,因为 WPF 使用它来将行置于编辑模式可能听起来合乎逻辑,但在现实世界中,这与每个实际应用程序的工作方式背道而驰。
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.
如果用户在他们的屏幕上看到一个复选框,他们应该能够点击它一次以勾选/取消勾选它。故事结局。
回答by Weidian Huang
There is a much simpler solution here.
这里有一个更简单的解决方案。
<DataGridTemplateColumn MinWidth="20" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<CheckBox VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
If you use DataGridCheckBoxColumn
to implement, first click is to focus, second click is to check.
如果你DataGridCheckBoxColumn
用来实现,第一次点击是对焦,第二次点击是检查。
But using DataGridTemplateColumn
to implement needs one click only.
但是使用DataGridTemplateColumn
实现只需要一键即可。
The difference of using DataGridComboboxBoxColumn
and implementation by DataGridTemplateColumn
is also similar.
usingDataGridComboboxBoxColumn
和实现 by的区别DataGridTemplateColumn
也是类似的。
回答by Darlan Dieterich
I solved with this:
我用这个解决了:
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Viewbox Height="25">
<CheckBox IsChecked="{Binding TheProperty, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
</Viewbox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
The checkbox active on single click!
单击激活复选框!
回答by Rafal Spacjer
Base on Jim Adornoanswer and comments on his post, this is solution with MultiTrigger
:
基于吉姆·阿多诺( Jim Adorno) 的回答和对他的帖子的评论,这是解决方案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>
回答by AmirHossein Rezaei
Yet another simple solution is to add this style to your DataGridColumn.The body of your style can be empty.
另一个简单的解决方案是将此样式添加到您的 DataGridColumn。您的样式主体可以为空。
<DataGridCheckBoxColumn>
<DataGridCheckBoxColumn.ElementStyle>
<Style TargetType="CheckBox">
</Style>
</DataGridCheckBoxColumn.ElementStyle>
</DataGridCheckBoxColumn>