DataGridComboBoxColumn -单击自动下拉
本文关键字:单击 DataGridComboBoxColumn | 更新日期: 2023-09-27 18:13:50
我在DataGrid中有一个datagridcomboboxcolumn。我想能够点击单元格一次,并有组合框下拉。目前我必须点击多次。
<DataGrid AutoGenerateColumns="False" Height="148" HorizontalAlignment="Left" Margin="48,85,0,0" Name ="dg_display" VerticalAlignment="Top" Width="645" CanUserAddRows="False" CanUserDeleteRows="False" ItemsSource="{Binding}" SelectionChanged="DgDisplaySelectionChanged">
<DataGrid.Columns>
<DataGridTextColumn IsReadOnly="True" Header="Symbol" Binding="{Binding Symbol}" />
<DataGridTextColumn IsReadOnly="True" Header="Company ID" Binding="{Binding CompanyID}" />
<DataGridComboBoxColumn IsReadOnly="False" Header="Sector" SelectedValueBinding="{Binding Sector}" DisplayMemberPath="{Binding [0]}" Visibility="Visible" >
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding SectorList}" />
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding SectorList}" />
</Style>
</DataGridComboBoxColumn.ElementStyle>
</DataGridComboBoxColumn>
</DataGrid.Columns>
</DataGrid>
一键编辑DataGridComboBoxColumn +一键编辑CheckboxColumn
参见:https://stackoverflow.com/a/8333704/724944
<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;
}
两个答案都不适合我。下面的方法对我很有效。
<DataGridComboBoxColumn
Header="Example ComboBox"
DisplayMemberPath="Name"
SelectedValuePath="Id">
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="IsDropDownOpen" Value="True" />
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
我不记得我是从哪里得到这个答案的。有可能是堆栈溢出造成的。如果有人看到了原始来源,请随时发表评论。
我对@surfen的回答有问题,可能是因为它已经过去很多年了,WPF可能已经发生了很大的变化。似乎DataGrid
现在为你照顾一些事情,比如当你开始输入时自动编辑文本字段。
我使用DataGridTemplateColumn
作为组合框列。模板的CellTemplate
对应TextBlock
。对BeginEdit
的调用和对调度程序的调用将导致组合框出现在可视化树中。然后看起来鼠标点击被发送到组合框,它自己打开。
这是我修改过的@surfen的代码:
public static class DataGridExtensions
{
public static void FastEdit(this DataGrid dataGrid)
{
dataGrid.ThrowIfNull(nameof(dataGrid));
dataGrid.PreviewMouseLeftButtonDown += (sender, args) => { FastEdit(args.OriginalSource, args); };
}
private static void FastEdit(object source, RoutedEventArgs args)
{
var dataGridCell = (source as UIElement)?.FindVisualParent<DataGridCell>();
if (dataGridCell == null || dataGridCell.IsEditing || dataGridCell.IsReadOnly)
{
return;
}
var dataGrid = dataGridCell.FindVisualParent<DataGrid>();
if (dataGrid == null)
{
return;
}
if (!dataGridCell.IsFocused)
{
dataGridCell.Focus();
}
if (dataGridCell.Content is CheckBox)
{
if (dataGrid.SelectionUnit != DataGridSelectionUnit.FullRow)
{
if (!dataGridCell.IsSelected)
{
dataGridCell.IsSelected = true;
}
}
else
{
var dataGridRow = dataGridCell.FindVisualParent<DataGridRow>();
if (dataGridRow != null && !dataGridRow.IsSelected)
{
dataGridRow.IsSelected = true;
}
}
}
else
{
dataGrid.BeginEdit(args);
dataGridCell.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() => { }));
}
}
}
public static class UIElementExtensions
{
public static T FindVisualParent<T>(this UIElement element)
where T : UIElement
{
UIElement currentElement = element;
while (currentElement != null)
{
var correctlyTyped = currentElement as T;
if (correctlyTyped != null)
{
return correctlyTyped;
}
currentElement = VisualTreeHelper.GetParent(currentElement) as UIElement;
}
return null;
}
}
经过大量的研究,最终我发现Nathan的解决方案是目前为止最好的解决方案。然而,它有一个问题,如果你点击一个组合框列,下拉菜单被打开,但当前值没有被选中。
我最终解决了这个问题,并以更少的代码结束。注意,DataTemplate使用MouseLeftButtonDown事件来初始化"一键魔术"。在UI代码后面,感谢@NathanAldenSr
模板列解决方案的一个很好的副作用是,组合框项的数据源可能每行更改,即每行可能有一组不同的组合框项可用。
<DataGridTemplateColumn Header="ComboBox (TemplateColumn)">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox
ItemsSource="{Binding DataContext.MyComboBoxItems,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=Window}}"
SelectedValue="{Binding MyComboBoxValue,
Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsDropDownOpen="True" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock
Text="{Binding MyComboBoxValue, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
Padding="3"
MouseLeftButtonDown="FastEditEvent" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
后面的视图代码正在使用NathanAldenSr扩展方法代码:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void FastEditEvent(object sender, RoutedEventArgs args)
{
var dataGridCell = (sender as UIElement)?.FindVisualParent<DataGridCell>();
dataGridCell.FastEdit(args);
}
}
public static class DataGridExtensions
{
public static void FastEdit(this DataGridCell dataGridCell, RoutedEventArgs args)
{
if (dataGridCell == null || dataGridCell.IsEditing || dataGridCell.IsReadOnly)
{
return;
}
var dataGrid = dataGridCell.FindVisualParent<DataGrid>();
if (dataGrid == null)
{
return;
}
if (!dataGridCell.IsFocused)
{
dataGridCell.Focus();
}
dataGrid.Dispatcher.InvokeAsync(() =>
{
dataGrid.BeginEdit(args);
});
}
}
public static class UiElementExtensions
{
public static T FindVisualParent<T>(this UIElement element)
where T : UIElement
{
var currentElement = element;
while (currentElement != null)
{
if (currentElement is T correctlyTyped)
{
return correctlyTyped;
}
currentElement = VisualTreeHelper.GetParent(currentElement) as UIElement;
}
return null;
}
}