DataGrid 自定義DataGridColumnheader

在學習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";
        }
    }





      



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章