在學習DataGrid的過程中,發現自定義DataGridColumnheader 會非常必要,而且可以自定以column 模板。
本例子主要是自定義了Column Header, 自定義Column 內容顯示,可以對Column Header的排序和通過拖動header修改column的寬度.
1. 在xml 中添加如下資源
a. 帶有箭頭的datatemplate, 爲用戶點Header排序的時候可以顯示不同的箭頭
向上的箭頭data template:
<DataTemplate x:Key="ColumHeaderArrowUp">
<DockPanel>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding}"></TextBlock>
<Path x:Name="PT" Stroke="Gray" Fill="SeaGreen" RenderTransformOrigin="0.5,.5">
<Path.RenderTransform>
<RotateTransform x:Name="RT" Angle="0"></RotateTransform>
</Path.RenderTransform>
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="3.5,3">
<LineSegment Point="0,9"></LineSegment>
<LineSegment Point="7,9"></LineSegment>
<LineSegment Point="3.5,3"></LineSegment>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
</DockPanel>
</DataTemplate>
向下的箭頭 data template:
<DataTemplate x:Key="ColumHeaderArrowDown">
<DockPanel>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding}"></TextBlock>
<Path x:Name="PT" Stroke="Gray" Fill="SeaGreen" RenderTransformOrigin="0.5,0.5">
<Path.RenderTransform>
<RotateTransform x:Name="RT" Angle="180"></RotateTransform>
</Path.RenderTransform>
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="3.5,3">
<LineSegment Point="0,9"></LineSegment>
<LineSegment Point="7,9"></LineSegment>
<LineSegment Point="3.5,3"></LineSegment>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
</DockPanel>
</DataTemplate>
b. 添加數據資源
首先爲XML增加如下namespace:
xmlns:Local="clr-namespace:ImageVideoPlayer"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:sysModel="clr-namespace:System.ComponentModel;assembly=System"
增加性別資源, 需要在.cs文件中增加類 public class GenderCollection:ObservableCollection<string>{}
<Local:GenderCollection x:Key="gendercollection">
<sys:String>Man</sys:String>
<sys:String>Female</sys:String>
</Local:GenderCollection>
增加employee 信息, 在.cs文件中增加類 public class EmployeeCollection : ObservableCollection<Employee>{} <Local:EmployeeCollection x:Key="employeecollection">
<Local:Employee FirstName="A1" LastName="Micheal" bValid="True" Gender="Man" Number="1"></Local:Employee>
<Local:Employee FirstName="A2" LastName="Micheal" bValid="True" Gender="Man" Number="2"></Local:Employee>
<Local:Employee FirstName="A3" LastName="Micheal" bValid="True" Gender="Female" Number="3"></Local:Employee>
<Local:Employee FirstName="A4" LastName="Micheal" bValid="True" Gender="Female" Number="4"></Local:Employee>
</Local:EmployeeCollection>
c.添加header的style
<Style TargetType="DataGridColumnHeader" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Button Height="auto" Content="{Binding}" x:Name="Btn" Width="auto" Click="Btn_Click" MouseEnter="Btn_MouseEnter" MouseLeave="Btn_MouseLeave" MouseMove="Btn_MouseMove" PreviewMouseDown="Btn_PreviewMouseDown">
</Button>
<ControlTemplate.Triggers>
<Trigger Property="DataGridColumnHeader.SortDirection" Value="0">
<Setter Property="Button.ContentTemplate" TargetName="Btn" Value="{DynamicResource ColumHeaderArrowUp}"></Setter>
</Trigger>
<Trigger Property="DataGridColumnHeader.SortDirection" Value="1">
<Setter Property="Button.ContentTemplate" TargetName="Btn" Value="{DynamicResource ColumHeaderArrowDown}"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<EventSetter Event="Click" Handler="HeaderClickRoutedEventHandler"></EventSetter>
<EventSetter Event="DragOver" Handler="HeaderDragOverEventHandler"></EventSetter>
<EventSetter Event="Drop" Handler="HeaderDragDropEventHandler"></EventSetter>
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="HeaderMouseButtonEventHandler"></EventSetter>
</Style>
d. 添加DataGrid
<DataGrid x:Name="EmployeeGrid" HorizontalAlignment="Left" Margin="0" VerticalAlignment="Top" ItemsSource="{StaticResource employeecollection}" AutoGenerateColumns="False" AlternationCount="2"
MinColumnWidth="20" CanUserAddRows="False" CanUserResizeRows="False" CanUserSortColumns="True" SelectionUnit="FullRow" AllowDrop="True" SelectionMode="Single" CanUserReorderColumns="True" RowDetailsVisibilityMode="VisibleWhenSelected">
<DataGrid.Columns>
<DataGridTextColumn Header="Number" Binding="{Binding Number}"></DataGridTextColumn>
<DataGridTextColumn Header="First Name" Binding="{Binding FirstName}"></DataGridTextColumn>
<DataGridTextColumn Header="Last Name" Binding="{Binding LastName}"></DataGridTextColumn>
<DataGridTemplateColumn Header="Gender" SortMemberPath="{Binding Gender}">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Gender}"></TextBlock>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<StackPanel>
<ComboBox ItemsSource="{StaticResource gendercollection}" SelectedItem="{Binding Gender}"></ComboBox>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridCheckBoxColumn Header="Valid" Binding="{Binding bValid}">
</DataGridCheckBoxColumn>
</DataGrid.Columns>
</DataGrid>
2. 在.cs文件中內容
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ImageVideoPlayer
{
/// <summary>
/// Interaction logic for GridDragDropManual.xaml
/// </summary>
public partial class GridDragDropManual : UserControl
{
public GridDragDropManual()
{
InitializeComponent();
}
#region helper
public void SortColumn(string header, bool bAescending)
{
var employees = this.grid.Resources["employeecollection"] as EmployeeCollection;
var tempList = new List<Employee>();
tempList.AddRange(employees);
tempList.Sort((x, y) =>
{
var tempX = x;
var tempY = y;
if(bAescending)
{
tempX = y;
tempY = x;
}
if (header.Contains("First"))
return tempX.FirstName.CompareTo(tempY.FirstName);
else if (header.Contains("Last"))
return tempX.LastName.CompareTo(tempY.LastName);
else if (header.Contains("Number"))
return tempX.Number.CompareTo(tempY.Number);
else if (header.Contains("Gender"))
return tempX.Gender.CompareTo(tempY.Gender);
else if(header.Contains("Valid"))
return tempX.bValid.CompareTo(tempY.bValid);
return 0;
});
employees.Clear();
foreach(var tmp in tempList)
{
employees.Add(tmp);
}
}
void ClearSort()
{
foreach (var clm in this.EmployeeGrid.Columns)
{
//clm.HeaderTemplate = null;
clm.SortDirection = null;
}
}
#endregion
#region event
public static readonly DependencyProperty DPbUp = DependencyProperty.Register("bUp", typeof(bool), typeof(GridDragDropManual));
bool _bUp = true;
bool bUp
{
get { return (bool)GetValue(DPbUp); }
set { SetValue(DPbUp,value); }
}
bool bColumnResize = false;
int ResizeIndex;
void HeaderClickRoutedEventHandler(object sender, System.Windows.RoutedEventArgs e)
{
if (bColumnResize) return;
var header = sender as DataGridColumnHeader;
if (header == null) return;
SortColumn(header.Content as string, bUp);
bUp = !bUp;
_bUp = bUp;
ClearSort();
header.Column.SortDirection = bUp ? ListSortDirection.Ascending : ListSortDirection.Descending;
this.EmployeeGrid.CurrentColumn = header.Column;
}
private void HeaderDragOverEventHandler(object sender, System.Windows.DragEventArgs e)
{
}
private void HeaderDragDropEventHandler(object sender, System.Windows.DragEventArgs e)
{
}
private void HeaderMouseButtonEventHandler(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
}
#endregion
private void Btn_Click(object sender, RoutedEventArgs e)
{
}
private void Btn_MouseEnter(object sender, MouseEventArgs e)
{
}
private void Btn_MouseLeave(object sender, MouseEventArgs e)
{
if (bColumnResize)
{
Cursor = Cursors.Arrow;
bColumnResize = false;
}
}
Point oldPos;
private void Btn_MouseMove(object sender, MouseEventArgs e)
{
var btn = sender as Button;
if (btn == null) return;
var pos = e.GetPosition(btn);
var rect = VisualTreeHelper.GetDescendantBounds(btn);
var parent = VisualTreeHelper.GetParent(btn);
while(parent != null)
{
if(parent is DataGridColumnHeader)
{
break;
}
parent = VisualTreeHelper.GetParent(parent);
}
if(parent == null)
return;
var header = parent as DataGridColumnHeader;
if (e.LeftButton == MouseButtonState.Pressed)
{
if (bColumnResize && header.Column.DisplayIndex == ResizeIndex)
{
header.Column.Width = new DataGridLength(header.Column.ActualWidth + pos.X - oldPos.X);
oldPos = pos;
}
else
bColumnResize = false;
}
else
{
oldPos = pos;
rect.Inflate(0, -3);
bool bDragArea = false;
if (rect.Contains(pos))
{
if ((rect.Right - pos.X) < 10)
{
bDragArea = true;
}
}
if (bDragArea)
{
Cursor = Cursors.SizeWE;
if (!bColumnResize)
{
bColumnResize = true;
ResizeIndex = header.Column.DisplayIndex;
}
}
else
bColumnResize = false;
}
if (!bColumnResize)
{
Cursor = Cursors.Arrow;
ResizeIndex = -1;
}
}
private void Btn_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if (bColumnResize)
e.Handled = true;
if(bColumnResize)
{
var btn = sender as Button;
oldPos = e.GetPosition(btn);
}
}
}
public class GenderCollection:ObservableCollection<string>
{
}
public class EmployeeCollection : ObservableCollection<Employee>
{
}
public class Employee
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Number { get; set; }
public string Gender { get; set; }
public bool bValid { get; set; }
public Employee()
{
bValid = true;
Gender = "Man";
}
}