Reputation: 5043
I am using WPF DataGrid and I would like to allow the user to select an entire column by clicking on the column header. I currently have the SelectionUnit set to CellOrRowHeader because I want the same functionality for rows (which works great). Is there an easy way to also allow selection of columns by clicking the column header?
Upvotes: 3
Views: 6362
Reputation: 21
In WPF there is no direct support for column selection so, need to Extend existing DataGrid and add custom support for Column Selection. Below is the code that will allow used to select column on Header click. For Below code to work following setting is required.
Xaml Code:
<local:DataGridEx SelectionUnit="CellOrRowHeader" CanUserSortColumns="False"/>
C# Code:
public class DataGridEx : DataGrid
{
/// <summary>
/// Holds the column that is selected.
/// </summary>
public object SelectedColumn
{
get { return GetValue(SelectedColumnProperty); }
set { SetValue(SelectedColumnProperty, value); }
}
// Using a DependencyProperty as the backing store for SelectedColumn. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SelectedColumnProperty =
DependencyProperty.Register("SelectedColumn", typeof(object),
typeof(DataGridEx), new PropertyMetadata(null));
private T GetVisualParent<T>(DependencyObject child) where T : Visual
{
DependencyObject parent = VisualTreeHelper.GetParent(child);
if (parent == null || parent is T)
{
return parent as T;
}
else
{
return GetVisualParent<T>(parent);
}
}
protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
{
DataGridColumnHeader dataGridColumnHeader = GetVisualParent<DataGridColumnHeader>(e.OriginalSource as DependencyObject);
if (dataGridColumnHeader == null)
{
return;
}
if (SelectedCells != null && SelectedCells.Count > 0)
{
UnselectAllCells();
SelectedCells.Clear();
}
SelectedColumn = dataGridColumnHeader.Column;
foreach (var item in this.Items)
{
this.SelectedCells.Add(new DataGridCellInfo(item, dataGridColumnHeader.Column));
}
base.OnPreviewMouseDown(e);
}
}
Upvotes: 1
Reputation: 1714
You could also modify the ColumnHeaderStyle
:
In XAML:
<DataGrid>
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<EventSetter Event="Click" Handler="DataGridColumnHeader_OnClick"></EventSetter>
</Style>
</DataGrid.ColumnHeaderStyle>
</DataGrid>
In the code-behind:
private void DataGridColumnHeader_OnClick(object sender, RoutedEventArgs e)
{
var columnHeader = sender as DataGridColumnHeader;
if (columnHeader != null)
{
if (!Keyboard.IsKeyDown(Key.LeftCtrl))
{
dataGrid.SelectedCells.Clear();
}
foreach (var item in dataGrid.Items)
{
dataGrid.SelectedCells.Add(new DataGridCellInfo(item, columnHeader.Column));
}
}
}
Upvotes: 1
Reputation: 17145
You have many options. one is create your own Template for DataGrid's Header Style. Inside the DataTemplate tag you can change the template of the headers. (you can replace the Button with a TextBlock or anything you want.)
<DataGrid>
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader" >
<Setter Property="Foreground" Value="Blue" />
<Setter Property="ContentTemplate" >
<Setter.Value>
<DataTemplate>
<Button Content={Binding Content}" MouseDown="mouseDownEventHandler">
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.ColumnHeaderStyle>
</DataGrid>
or if you are using DataGrid.Columns to populate your columns and you need to set each of them separately, you can use this:
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn HeaderTemplate="{StaticResource MyTemplate1"/>
<DataGridHyperlinkColumn HeaderTemplate="{StaticResource MyTemplate2"/>
</DataGrid.Columns>
</DatGrid>
where MyTemplate1 and 2 should be defined previously in your control's Resources.
Edit:
The other approach according to this link is to add a PreviewMouseDown to your DataGrid and then find out if the mouse down was happend on the header or not.
This is the simple version of her event handler:
DependencyObject dep = (DependencyObject)e.OriginalSource;
while ((dep != null) && !(dep is DataGridColumnHeader))
{
dep = VisualTreeHelper.GetParent(dep);
}
if (dep == null) return;
if (dep is DataGridColumnHeader)
{
MessageBox.Show(((DataGridColumnHeader)dep).Content.ToString());
}
Upvotes: 2