WPF DataGridTable

由于项目要显示表头合并,而数据源列随时变更,又不想重复的画表格,就实现动态数据(dynamic)绑定和配置数据列模板的方式

编辑DataGridColumnHeader样式实现表头合并:效果如下

实现思路:

在表头中插入一个Grid,Grid列跟HeaderColmun列数相等,并关联HeaderColmun的SizeChanged事件,Colmun列大小发生变化时,合并的头模板也会跟着移动。

 <Grid x:Name="PART_ColumnHeadersPresenter_Grid"
                                  Height="30"
                                  ShowGridLines="False">
                            </Grid>
   Dictionary<DataGridColumnHeader, ColumnDefinition> dictCols = new Dictionary<DataGridColumnHeader, ColumnDefinition>();

        private void DataGridTitleSpan_Loaded(object sender, RoutedEventArgs e)
        {
            var hdCols = WPFVisualTreeHelper.GetChildByName<DataGridColumnHeadersPresenter>(this, "PART_ColumnHeadersPresenter");
            var grid = WPFVisualTreeHelper.GetChildByName<Grid>(this, "PART_ColumnHeadersPresenter_Grid");
            if (grid == null)
            {
                return;
            }
            //grid.Visibility = Visibility.Collapsed;
            //if (DataSouceGridHeaderColTemplate == null || DataSouceGridHeaderColTemplate.Count == 0)
            //{
            //    grid.Visibility = Visibility.Collapsed;
            //}
            var hdItem = WPFVisualTreeHelper.FindVisualChild<DataGridCellsPanel>(hdCols);
            var header = hdItem.FirstOrDefault();
            if (header != null)
            {
                foreach (var item in header.Children)
                {
                    var vHd = item as DataGridColumnHeader;
                    vHd.SizeChanged += VHd_SizeChanged;
                    ColumnDefinition rd = new ColumnDefinition();
                    rd.Width = new GridLength(vHd.ActualWidth, GridUnitType.Pixel);
                    grid.ColumnDefinitions.Add(rd);
                    dictCols[vHd] = rd;
                }
            }
            GenerateHeader(DataSouceGridHeaderColTemplate, grid);
        }

        private void VHd_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            var vHd = sender as DataGridColumnHeader;
            if (dictCols.ContainsKey(vHd))
            {
                dictCols[vHd].Width = new GridLength(vHd.ActualWidth, GridUnitType.Pixel);
            }
        }

 

下面是完整的HeaderColmun列模板

<Style x:Key="DataGridColumnHeaderStyle_Colspan"
           TargetType="{x:Type DataGridColumnHeader}">
        <Setter Property="VerticalContentAlignment"
                Value="Center" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
                    <!--<Grid>
                        <Themes:DataGridHeaderBorder BorderBrush="{TemplateBinding BorderBrush}"
                                                     BorderThickness="{TemplateBinding BorderThickness}"
                                                     Background="{TemplateBinding Background}"
                                                     IsClickable="{TemplateBinding CanUserSort}"
                                                     IsPressed="{TemplateBinding IsPressed}"
                                                     IsHovered="{TemplateBinding IsMouseOver}"
                                                     Padding="{TemplateBinding Padding}"
                                                     SortDirection="{TemplateBinding SortDirection}"
                                                     SeparatorBrush="{TemplateBinding SeparatorBrush}"
                                                     SeparatorVisibility="{TemplateBinding SeparatorVisibility}">
                            <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                              RecognizesAccessKey="True"
                                              SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                        </Themes:DataGridHeaderBorder>
                        <Thumb x:Name="PART_LeftHeaderGripper"
                               HorizontalAlignment="Left"
                               Style="{StaticResource ColumnHeaderGripperStyle}" />
                        <Thumb x:Name="PART_RightHeaderGripper"
                               HorizontalAlignment="Right"
                               Style="{StaticResource ColumnHeaderGripperStyle}" />
                    </Grid>-->
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"></RowDefinition>
                            <RowDefinition Height="*"></RowDefinition>
                        </Grid.RowDefinitions>
                        <Border BorderBrush="{Binding BorderBrush,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGrid}}}"
                                Padding="{TemplateBinding Padding}"
                                BorderThickness="0 0 0 1"
                                Grid.Row="0"
                                Visibility="{Binding Path=ColspanVisibility,RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}">
                            <Grid x:Name="PART_ColumnHeadersPresenter_Grid"
                                  Height="30"
                                  ShowGridLines="False">
                            </Grid>
                        </Border>
                        <Grid Grid.Row="1">
                            <Themes:DataGridHeaderBorder BorderBrush="{Binding BorderBrush,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGrid}}}"
                                                         BorderThickness="0 0 1 1"
                                                         Background="Transparent"
                                                         IsClickable="{TemplateBinding CanUserSort}"
                                                         IsPressed="{TemplateBinding IsPressed}"
                                                         IsHovered="{TemplateBinding IsMouseOver}"
                                                         Padding="{TemplateBinding Padding}"
                                                         SortDirection="{TemplateBinding SortDirection}"
                                                         SeparatorBrush="{TemplateBinding SeparatorBrush}"
                                                         SeparatorVisibility="{TemplateBinding SeparatorVisibility}">
                                <ContentPresenter HorizontalAlignment="{Binding HorizontalContentAlignment,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGrid}}}"
                                                  RecognizesAccessKey="True"
                                                  SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                            </Themes:DataGridHeaderBorder>
                            <Thumb x:Name="PART_LeftHeaderGripper"
                                   HorizontalAlignment="Left"
                                   Style="{StaticResource ColumnHeaderGripperStyle}" />
                            <Thumb x:Name="PART_RightHeaderGripper"
                                   HorizontalAlignment="Right"
                                   Style="{StaticResource ColumnHeaderGripperStyle}" />
                        </Grid>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

关键代码如下:

显示的View Xaml和Code

<UserControl x:Class="YunTong46View.Usr_TestDataGridTableView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:local="clr-namespace:YunTong46View"
             mc:Ignorable="d"
             d:DesignHeight="300"
             d:DesignWidth="300">
    <UserControl.Resources>
        <ResourceDictionary Source="Themes/DataGridStyle.xaml">
        </ResourceDictionary>
    </UserControl.Resources>
    <StackPanel>
        <StackPanel  Margin="20 15 20 10">
            <TextBlock Text="出现滚动条:数据绑定"
                       Foreground="Red"
                       FontSize="20"></TextBlock>
            <local:DataGridTitleSpan   x:Name="dataGridTitle2"
                                       Width="500"
                                       Height="200"
                                       VerticalAlignment="Top"
                                       HorizontalAlignment="Left"
                                       ScrollViewer.HorizontalScrollBarVisibility="Visible"
                                       ScrollViewer.VerticalScrollBarVisibility="Visible"
                                       DataSouceGridHeaderColTemplate="{Binding Headers0}"
                                       ItemsSource="{Binding DataSource}">
            </local:DataGridTitleSpan>
        </StackPanel>
        <StackPanel  Margin="20 10">
            <TextBlock Text="dynamic动态类数据绑定不支持排序"
                       Foreground="Red"
                       FontSize="20"></TextBlock>
            <local:DataGridTitleSpan   x:Name="dataGridTitle"
                                       Height="200"
                                       ScrollViewer.HorizontalScrollBarVisibility="Visible"
                                       ScrollViewer.VerticalScrollBarVisibility="Visible"
                                       DataSouceGridHeaderColTemplate="{Binding Headers0}">
            </local:DataGridTitleSpan>
        </StackPanel>

        <StackPanel  Margin="20 10">
            <TextBlock Text="引用样式"
                       Foreground="Red"
                       FontSize="20"></TextBlock>
            <DataGrid    x:Name="dataGrid"
                         Height="200"
                         Style="{DynamicResource DataGridStyle_Colspan}"
                         ItemsSource="{Binding DataSource}"
                         Visibility="Visible">
            </DataGrid>
        </StackPanel>

        <StackPanel  Margin="20 10">
            <TextBlock Text="原生DataGrid"
                       Foreground="Red"
                       FontSize="20"></TextBlock>
            <DataGrid    x:Name="dataGrid2"
                         Height="200"
                         BorderBrush="Blue"
                         AutoGenerateColumns="False"
                         HorizontalGridLinesBrush="Blue"
                         VerticalGridLinesBrush="Blue"
                         ItemsSource="{Binding DataSource}">
            </DataGrid>
        </StackPanel>
    </StackPanel>
</UserControl>
View Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
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 YunTong46View
{
    /// <summary>
    /// Usr_YunTong46MainView.xaml 的交互逻辑
    /// </summary>
    public partial class Usr_TestDataGridTableView : UserControl
    {
        ViewMode viewMode = new ViewMode();
        public Usr_TestDataGridTableView()
        {
            InitializeComponent();
            viewMode.Init();
            this.DataContext = viewMode;
            SetHeaderTemplates(dataGridTitle, viewMode.Headers1);
            SetHeaderTemplates(dataGridTitle2, viewMode.Headers1);
            SetHeaderTemplates(dataGrid, viewMode.Headers1);
            SetHeaderTemplates(dataGrid2, viewMode.Headers1);
            this.Loaded += Usr_YunTong46MainView_Loaded;
        }

        private void Usr_YunTong46MainView_Loaded(object sender, RoutedEventArgs e)
        {
            var json = JsonHelper.SerializeObject(viewMode.DataSource);
            var dyDatas = JsonHelper.DeserializeObject<dynamic>(json);
            dataGridTitle.ItemsSource = dyDatas;
        }

        private void SetHeaderTemplates(DataGrid dataGrid, List<HeaderTemplate> headers)
        {
            foreach (var item in headers)
            {
                var col = new DataGridTextColumn();
                col.Header = item.HeaderName;
                var bind = new Binding();
                bind.Path = new PropertyPath(item.PropertyName);
                if (!string.IsNullOrEmpty(item.PropertyFormat))
                {
                    //bind.StringFormat = "{}{0:" + item.PropertyFormat + "}}";
                    bind.StringFormat = item.PropertyFormat.Trim();
                }
                col.Binding = bind;
                DataGridLengthUnitType unType = DataGridLengthUnitType.Auto;
                double width = 0;
                if (item.ColmunUnitType == "p")
                {
                    unType = DataGridLengthUnitType.Pixel;
                    width = item.ColmunWidth;
                }
                else if (item.ColmunUnitType == "s")
                {
                    unType = DataGridLengthUnitType.Star;
                    width = item.ColmunWidth;
                }
                if (width < 0)
                {
                    width = 0;
                }
                col.Width = new DataGridLength(width, unType);
                dataGrid.Columns.Add(col);
            }
        }
    }
    public class ViewMode
    {
        private List<HeaderTemplate> _headers0 = new List<HeaderTemplate>();
        private List<HeaderTemplate> _headers1 = new List<HeaderTemplate>();
        private List<DataModel> _dataSource = new List<DataModel>();

        public List<HeaderTemplate> Headers0
        {
            get
            {
                return _headers0;
            }

            set
            {
                _headers0 = value;
            }
        }

        public List<HeaderTemplate> Headers1
        {
            get
            {
                return _headers1;
            }

            set
            {
                _headers1 = value;
            }
        }

        public List<DataModel> DataSource
        {
            get
            {
                return _dataSource;
            }

            set
            {
                _dataSource = value;
            }
        }

        public void Init()
        {
            _headers0.Add(new HeaderTemplate() { ColmunIndex = 0, ColmunSpan = 4, HeaderName = "故障登记时间及状态" });
            _headers0.Add(new HeaderTemplate() { ColmunIndex = 0, ColmunSpan = 4, HeaderName = "通知时间及通知方法" });
            _headers0.Add(new HeaderTemplate() { ColmunIndex = 0, ColmunSpan = 3, HeaderName = "到达时间及签名" });
            _headers0.Add(new HeaderTemplate() { ColmunIndex = 0, ColmunSpan = 3, HeaderName = "消除不良及破损后的时间和方法" });


            _headers1.Add(new HeaderTemplate() { ColmunIndex = 0, ColmunSpan = 0, PropertyName = "GZDT", PropertyFormat = "MM-dd", ColmunUnitType = "a", ColmunWidth = 1, HeaderName = "月日" });
            _headers1.Add(new HeaderTemplate() { ColmunIndex = 1, ColmunSpan = 0, PropertyName = "GZDT", PropertyFormat = "HH:mm", ColmunUnitType = "a", ColmunWidth = 1, HeaderName = "时分" });
            _headers1.Add(new HeaderTemplate() { ColmunIndex = 2, ColmunSpan = 0, PropertyName = "GZDeviceName", ColmunUnitType = "a", ColmunWidth = 1, HeaderName = "设备名称" });
            _headers1.Add(new HeaderTemplate() { ColmunIndex = 3, ColmunSpan = 0, PropertyName = "GZStatus", ColmunUnitType = "a", ColmunWidth = 1, HeaderName = "故障状态" });

            _headers1.Add(new HeaderTemplate() { ColmunIndex = 4, ColmunSpan = 0, PropertyName = "TZDW", ColmunUnitType = "a", ColmunWidth = 1, HeaderName = "通知单位" });
            _headers1.Add(new HeaderTemplate() { ColmunIndex = 5, ColmunSpan = 0, PropertyName = "TZDT", PropertyFormat = "MM-dd", ColmunUnitType = "a", ColmunWidth = 1, HeaderName = "月日" });
            _headers1.Add(new HeaderTemplate() { ColmunIndex = 6, ColmunSpan = 0, PropertyName = "TZDT", PropertyFormat = "HH:mm", ColmunUnitType = "a", ColmunWidth = 1, HeaderName = "时分" });
            _headers1.Add(new HeaderTemplate() { ColmunIndex = 7, ColmunSpan = 0, PropertyName = "TZFF", ColmunUnitType = "a", ColmunWidth = 1, HeaderName = "通知方法" });

            _headers1.Add(new HeaderTemplate() { ColmunIndex = 8, ColmunSpan = 0, PropertyName = "DDDT", PropertyFormat = "MM-dd", ColmunUnitType = "a", ColmunWidth = 1, HeaderName = "月日" });
            _headers1.Add(new HeaderTemplate() { ColmunIndex = 9, ColmunSpan = 0, PropertyName = "DDDT", PropertyFormat = "HH:mm", ColmunUnitType = "a", ColmunWidth = 1, HeaderName = "时分" });
            _headers1.Add(new HeaderTemplate() { ColmunIndex = 10, ColmunSpan = 0, PropertyName = "DDQM", ColmunUnitType = "a", ColmunWidth = 1, HeaderName = "该段工作人员到达后签名" });

            _headers1.Add(new HeaderTemplate() { ColmunIndex = 11, ColmunSpan = 0, PropertyName = "BLDT", PropertyFormat = "MM-dd", ColmunUnitType = "a", ColmunWidth = 1, HeaderName = "月日" });
            _headers1.Add(new HeaderTemplate() { ColmunIndex = 12, ColmunSpan = 0, PropertyName = "BLDT", PropertyFormat = "HH:mm", ColmunUnitType = "a", ColmunWidth = 1, HeaderName = "时分" });
            _headers1.Add(new HeaderTemplate() { ColmunIndex = 13, ColmunSpan = 0, PropertyName = "BLTEXT", ColmunUnitType = "s", ColmunWidth = 10, HeaderName = "破损及不良的原因,采用何种方法进行\r;修理。工作人员及车站值班员签字" });

            for (int i = 0; i < 10; i++)
            {
                DataModel model = new DataModel();
                model.DDDT = DateTime.Now.AddMinutes(-1);
                model.GZDT = model.DDDT;
                model.TZDT = model.DDDT;
                model.BLDT = model.DDDT;
                model.GZDeviceName = "故障设备名称" + i.ToString();
                model.GZStatus = "故障状态" + i.ToString();
                model.TZDW = "通知单位" + i.ToString();
                model.TZFF = "通知方法" + i.ToString();
                model.DDQM = "到达签名" + i.ToString();
                model.BLTEXT = "不良内容" + i.ToString();
                _dataSource.Add(model);
            }
        }
    }

    public class DataModel
    {
        public DateTime GZDT { set; get; }

        public string GZDeviceName { set; get; }

        public string GZStatus { set; get; }

        public DateTime TZDT { set; get; }

        public string TZDW { set; get; }

        public string TZFF { set; get; }

        /// <summary>
        /// 到达时间
        /// </summary>
        public DateTime DDDT { set; get; }

        public string DDQM { set; get; }

        public DateTime BLDT { set; get; }

        public string BLTEXT { set; get; }
    }
}
View Code

DataTable样式和Code

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero">
    <Style x:Key="DataGridRowStyle_ColSpan"
           TargetType="{x:Type DataGridRow}">
        <Setter Property="Background"
                Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" />
        <Setter Property="SnapsToDevicePixels"
                Value="true" />
        <Setter Property="Validation.ErrorTemplate"
                Value="{x:Null}" />
        <Setter Property="ValidationErrorTemplate">
            <Setter.Value>
                <ControlTemplate>
                    <TextBlock Foreground="Red"
                               Margin="2,0,0,0"
                               Text="!"
                               VerticalAlignment="Center" />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type DataGridRow}">
                    <Border x:Name="DGR_Border"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            Background="{TemplateBinding Background}"
                            SnapsToDevicePixels="True">
                        <SelectiveScrollingGrid>
                            <SelectiveScrollingGrid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="*" />
                            </SelectiveScrollingGrid.ColumnDefinitions>
                            <SelectiveScrollingGrid.RowDefinitions>
                                <RowDefinition Height="*" />
                                <RowDefinition Height="Auto" />
                            </SelectiveScrollingGrid.RowDefinitions>
                            <Border Grid.Column="1"
                                    BorderThickness="1 0 0 0"
                                    BorderBrush="{Binding BorderBrush,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGrid}}}">
                                <DataGridCellsPresenter ItemsPanel="{TemplateBinding ItemsPanel}"
                                                        SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                            </Border>
                            <DataGridDetailsPresenter Grid.Column="1"
                                                      Grid.Row="1"
                                                      SelectiveScrollingGrid.SelectiveScrollingOrientation="{Binding AreRowDetailsFrozen, ConverterParameter={x:Static SelectiveScrollingOrientation.Vertical}, Converter={x:Static DataGrid.RowDetailsScrollingConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
                                                      Visibility="{TemplateBinding DetailsVisibility}" />
                            <!--隐藏左侧行号-->
                            <DataGridRowHeader Grid.RowSpan="2"
                                               SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical"
                                               Visibility="Collapsed" />
                        </SelectiveScrollingGrid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <Trigger Property="IsNewItem"
                     Value="True">
                <Setter Property="Margin"
                        Value="{Binding NewItemMargin, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
            </Trigger>
            <Trigger Property="IsSelected"
                     Value="True">
                <Setter Property="Background"
                        Value="#FFE8C91A" />
                <Setter Property="Foreground"
                        Value="Red" />
            </Trigger>
        </Style.Triggers>
    </Style>
    <Style x:Key="DataGridCellStyle_Colspan"
           TargetType="{x:Type DataGridCell}">
        <Setter Property="FontSize"
                Value="16" />
        <Setter Property="HorizontalContentAlignment"
                Value="Center"></Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type DataGridCell}">
                    <!--<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                      VerticalAlignment="Center"
                                      HorizontalAlignment="Center" />-->
                    <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />

                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <!--<Style.Triggers>
                        <Trigger Property="IsSelected"
                                 Value="True">
                            <Setter Property="Background"
                                    Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
                            <Setter Property="Foreground"
                                    Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}" />
                            <Setter Property="BorderBrush"
                                    Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
                        </Trigger>
                        <Trigger Property="IsMouseOver"
                                 Value="True">
                            <Setter Property="Background"
                                    Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
                        </Trigger>
                        <Trigger Property="IsKeyboardFocusWithin"
                                 Value="True">
                            <Setter Property="BorderBrush"
                                    Value="{DynamicResource {x:Static DataGrid.FocusBorderBrushKey}}" />
                        </Trigger>
                        <Trigger Property="IsSelected"
                                 Value="True">
                            <Setter Property="Foreground"
                                    Value="Black" />
                        </Trigger>
                    </Style.Triggers>-->
    </Style>
    <BooleanToVisibilityConverter x:Key="bool2VisibilityConverter" />
    <!--<Style x:Key="RowHeaderGripperStyle"
           TargetType="{x:Type Thumb}">
        <Setter Property="Height"
                Value="8" />
        <Setter Property="Background"
                Value="Transparent" />
        <Setter Property="Cursor"
                Value="SizeNS" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Thumb}">
                    <Border Background="{TemplateBinding Background}"
                            Padding="{TemplateBinding Padding}" />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>-->
    <Style x:Key="DataGridRowHeaderStyle_Colspan"
           TargetType="{x:Type DataGridRowHeader}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type DataGridRowHeader}">
                    <Grid>
                        <Themes:DataGridHeaderBorder BorderBrush="{TemplateBinding BorderBrush}"
                                                     BorderThickness="{TemplateBinding BorderThickness}"
                                                     Background="{TemplateBinding Background}"
                                                     IsPressed="{TemplateBinding IsPressed}"
                                                     IsHovered="{TemplateBinding IsMouseOver}"
                                                     IsSelected="{TemplateBinding IsRowSelected}"
                                                     Orientation="Horizontal"
                                                     Padding="{TemplateBinding Padding}"
                                                     SeparatorBrush="{TemplateBinding SeparatorBrush}"
                                                     SeparatorVisibility="{TemplateBinding SeparatorVisibility}">
                            <StackPanel Orientation="Horizontal">
                                <ContentPresenter RecognizesAccessKey="True"
                                                  SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                                  VerticalAlignment="Center" />
                                <Control SnapsToDevicePixels="false"
                                         Template="{Binding ValidationErrorTemplate, RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}}"
                                         Visibility="{Binding (Validation.HasError), Converter={StaticResource bool2VisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}}" />
                            </StackPanel>
                        </Themes:DataGridHeaderBorder>
                        <!--<Thumb x:Name="PART_TopHeaderGripper"
                               Style="{StaticResource RowHeaderGripperStyle}"
                               VerticalAlignment="Top" />
                        <Thumb x:Name="PART_BottomHeaderGripper"
                               Style="{StaticResource RowHeaderGripperStyle}"
                               VerticalAlignment="Bottom" />-->
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style x:Key="ColumnHeaderGripperStyle"
           TargetType="{x:Type Thumb}">
        <Setter Property="Width"
                Value="8" />
        <Setter Property="Background"
                Value="Transparent" />
        <Setter Property="Cursor"
                Value="SizeWE" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Thumb}">
                    <Border Background="{TemplateBinding Background}"
                            Padding="{TemplateBinding Padding}" />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style x:Key="DataGridColumnHeaderStyle_Colspan"
           TargetType="{x:Type DataGridColumnHeader}">
        <Setter Property="VerticalContentAlignment"
                Value="Center" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
                    <!--<Grid>
                        <Themes:DataGridHeaderBorder BorderBrush="{TemplateBinding BorderBrush}"
                                                     BorderThickness="{TemplateBinding BorderThickness}"
                                                     Background="{TemplateBinding Background}"
                                                     IsClickable="{TemplateBinding CanUserSort}"
                                                     IsPressed="{TemplateBinding IsPressed}"
                                                     IsHovered="{TemplateBinding IsMouseOver}"
                                                     Padding="{TemplateBinding Padding}"
                                                     SortDirection="{TemplateBinding SortDirection}"
                                                     SeparatorBrush="{TemplateBinding SeparatorBrush}"
                                                     SeparatorVisibility="{TemplateBinding SeparatorVisibility}">
                            <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                              RecognizesAccessKey="True"
                                              SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                        </Themes:DataGridHeaderBorder>
                        <Thumb x:Name="PART_LeftHeaderGripper"
                               HorizontalAlignment="Left"
                               Style="{StaticResource ColumnHeaderGripperStyle}" />
                        <Thumb x:Name="PART_RightHeaderGripper"
                               HorizontalAlignment="Right"
                               Style="{StaticResource ColumnHeaderGripperStyle}" />
                    </Grid>-->
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"></RowDefinition>
                            <RowDefinition Height="*"></RowDefinition>
                        </Grid.RowDefinitions>
                        <Border BorderBrush="{Binding BorderBrush,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGrid}}}"
                                Padding="{TemplateBinding Padding}"
                                BorderThickness="0 0 0 1"
                                Grid.Row="0"
                                Visibility="{Binding Path=ColspanVisibility,RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}">
                            <Grid x:Name="PART_ColumnHeadersPresenter_Grid"
                                  Height="30"
                                  ShowGridLines="False">
                            </Grid>
                        </Border>
                        <Grid Grid.Row="1">
                            <Themes:DataGridHeaderBorder BorderBrush="{Binding BorderBrush,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGrid}}}"
                                                         BorderThickness="0 0 1 1"
                                                         Background="Transparent"
                                                         IsClickable="{TemplateBinding CanUserSort}"
                                                         IsPressed="{TemplateBinding IsPressed}"
                                                         IsHovered="{TemplateBinding IsMouseOver}"
                                                         Padding="{TemplateBinding Padding}"
                                                         SortDirection="{TemplateBinding SortDirection}"
                                                         SeparatorBrush="{TemplateBinding SeparatorBrush}"
                                                         SeparatorVisibility="{TemplateBinding SeparatorVisibility}">
                                <ContentPresenter HorizontalAlignment="{Binding HorizontalContentAlignment,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGrid}}}"
                                                  RecognizesAccessKey="True"
                                                  SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                            </Themes:DataGridHeaderBorder>
                            <Thumb x:Name="PART_LeftHeaderGripper"
                                   HorizontalAlignment="Left"
                                   Style="{StaticResource ColumnHeaderGripperStyle}" />
                            <Thumb x:Name="PART_RightHeaderGripper"
                                   HorizontalAlignment="Right"
                                   Style="{StaticResource ColumnHeaderGripperStyle}" />
                        </Grid>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style x:Key="DataGridStyle_Colspan"
           TargetType="{x:Type DataGrid}">
        <Setter Property="Background"
                Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />
        <Setter Property="Foreground"
                Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
        <Setter Property="BorderBrush"
                Value="#FF688CAF" />
        <Setter Property="HorizontalContentAlignment"
                Value="Center"></Setter>
        <Setter Property="BorderThickness"
                Value="0" />
        <Setter Property="RowDetailsVisibilityMode"
                Value="VisibleWhenSelected" />
        <Setter Property="ScrollViewer.CanContentScroll"
                Value="true" />
        <Setter Property="ScrollViewer.PanningMode"
                Value="Both" />
        <Setter Property="Stylus.IsFlicksEnabled"
                Value="False" />
        <Setter Property="CanUserAddRows"
                Value="False" />
        <Setter Property="BorderBrush"
                Value="Blue">
        </Setter>
        <Setter Property="HorizontalGridLinesBrush"
                Value="Blue">
        </Setter>
        <Setter Property="VerticalGridLinesBrush"
                Value="Blue">
        </Setter>
        <Setter Property="AutoGenerateColumns"
                Value="False">
        </Setter>
        <Setter Property="TextBlock.TextAlignment"
                Value="Center">
        </Setter>
        <Setter Property="RowHeaderStyle"
                Value="{StaticResource DataGridRowHeaderStyle_Colspan}">
        </Setter>
        <Setter Property="RowStyle"
                Value="{StaticResource DataGridRowStyle_ColSpan}">
        </Setter>
        <Setter Property="ColumnHeaderStyle"
                Value="{StaticResource DataGridColumnHeaderStyle_Colspan}">
        </Setter>
        <Setter Property="CellStyle"
                Value="{StaticResource DataGridCellStyle_Colspan}">
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type DataGrid}">
                    <Border BorderBrush="{TemplateBinding BorderBrush}"
                            Background="{TemplateBinding Background}"
                            Padding="{TemplateBinding Padding}"
                            SnapsToDevicePixels="True"
                            x:Name="bd_Out">
                        <ScrollViewer x:Name="DG_ScrollViewer"
                                      Focusable="false">
                            <ScrollViewer.Template>
                                <ControlTemplate TargetType="{x:Type ScrollViewer}">
                                    <Grid>
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="Auto" />
                                            <ColumnDefinition Width="*" />
                                            <ColumnDefinition Width="Auto" />
                                        </Grid.ColumnDefinitions>
                                        <Grid.RowDefinitions>
                                            <RowDefinition Height="Auto" />
                                            <RowDefinition Height="*" />
                                            <RowDefinition Height="Auto" />
                                        </Grid.RowDefinitions>
                                        <Button Command="{x:Static DataGrid.SelectAllCommand}"
                                                Focusable="false"
                                                Style="{DynamicResource {ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}}"
                                                Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.All}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
                                                Width="{Binding CellsPanelHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
                                        <Border BorderThickness="1 1 1 0"
                                                Margin="-1 0 0 0"
                                                BorderBrush="{Binding BorderBrush,ElementName=bd_Out}"
                                                Grid.Column="1">
                                            <DataGridColumnHeadersPresenter x:Name="PART_ColumnHeadersPresenter"
                                                                            Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.Column}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
                                        </Border>
                                        <ScrollContentPresenter x:Name="PART_ScrollContentPresenter"
                                                                CanContentScroll="{TemplateBinding CanContentScroll}"
                                                                Grid.ColumnSpan="2"
                                                                Grid.Row="1" />
                                        <ScrollBar x:Name="PART_VerticalScrollBar"
                                                   Grid.Column="2"
                                                   Maximum="{TemplateBinding ScrollableHeight}"
                                                   Orientation="Vertical"
                                                   Grid.Row="1"
                                                   Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
                                                   Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"
                                                   ViewportSize="{TemplateBinding ViewportHeight}" />
                                        <Grid Grid.Column="1"
                                              Grid.Row="2">
                                            <Grid.ColumnDefinitions>
                                                <ColumnDefinition Width="{Binding NonFrozenColumnsViewportHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
                                                <ColumnDefinition Width="*" />
                                            </Grid.ColumnDefinitions>
                                            <ScrollBar x:Name="PART_HorizontalScrollBar"
                                                       Grid.Column="1"
                                                       Maximum="{TemplateBinding ScrollableWidth}"
                                                       Orientation="Horizontal"
                                                       Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"
                                                       Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"
                                                       ViewportSize="{TemplateBinding ViewportWidth}" />
                                        </Grid>
                                    </Grid>
                                </ControlTemplate>
                            </ScrollViewer.Template>
                            <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                        </ScrollViewer>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="IsGrouping"
                               Value="true" />
                    <Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping"
                               Value="false" />
                </MultiTrigger.Conditions>
                <Setter Property="ScrollViewer.CanContentScroll"
                        Value="false" />
            </MultiTrigger>
        </Style.Triggers>
    </Style>
</ResourceDictionary>
View Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 YunTong46View
{
    /// <summary>
    /// 按照步骤 1a 或 1b 操作,然后执行步骤 2 以在 XAML 文件中使用此自定义控件。
    ///
    /// 步骤 1a) 在当前项目中存在的 XAML 文件中使用该自定义控件。
    /// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根 
    /// 元素中: 
    ///
    ///     xmlns:MyNamespace="clr-namespace:YunTong46View"
    ///
    ///
    /// 步骤 1b) 在其他项目中存在的 XAML 文件中使用该自定义控件。
    /// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根 
    /// 元素中: 
    ///
    ///     xmlns:MyNamespace="clr-namespace:YunTong46View;assembly=YunTong46View"
    ///
    /// 您还需要添加一个从 XAML 文件所在的项目到此项目的项目引用,
    /// 并重新生成以避免编译错误: 
    ///
    ///     在解决方案资源管理器中右击目标项目,然后依次单击
    ///     “添加引用”->“项目”->[浏览查找并选择此项目]
    ///
    ///
    /// 步骤 2)
    /// 继续操作并在 XAML 文件中使用控件。
    ///
    ///     <MyNamespace:DataGridTitleSpan/>
    ///
    /// </summary>
    public class DataGridTitleSpan : DataGrid
    {
        ResourceDictionary rs = new ResourceDictionary();
        static DataGridTitleSpan()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(DataGridTitleSpan), new FrameworkPropertyMetadata(typeof(DataGridTitleSpan)));
        }

        public DataGridTitleSpan() : base()
        {
            rs.Source = new Uri("/YunTong46View;component/Themes/DataGridStyle.xaml", UriKind.Relative);
            //RowHeaderStyle = rs["DataGridRowHeaderStyle_Colspan"] as Style;
            //RowStyle = rs["DataGridRowStyle_ColSpan"] as Style;
            //ColumnHeaderStyle = rs["DataGridColumnHeaderStyle_Colspan"] as Style;
            var style = rs["DataGridStyle_Colspan"] as Style;
            this.Style = style;
            this.Loaded += DataGridTitleSpan_Loaded;
        }

        public List<HeaderTemplate> DataSouceGridHeaderColTemplate
        {
            get { return (List<HeaderTemplate>)GetValue(DataSouceGridHeaderColTemplateProperty); }
            set { SetValue(DataSouceGridHeaderColTemplateProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DataSouceGridHeaderTemplate.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DataSouceGridHeaderColTemplateProperty =
            DependencyProperty.Register("DataSouceGridHeaderColTemplate", typeof(List<HeaderTemplate>), typeof(DataGridTitleSpan), new PropertyMetadata(null));



        public Visibility ColspanVisibility
        {
            get { return (Visibility)GetValue(ColspanVisibilityProperty); }
            set { SetValue(ColspanVisibilityProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ColspanVisibility.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ColspanVisibilityProperty =
            DependencyProperty.Register("ColspanVisibility", typeof(Visibility), typeof(DataGridTitleSpan), new PropertyMetadata(Visibility.Visible));


        Dictionary<DataGridColumnHeader, ColumnDefinition> dictCols = new Dictionary<DataGridColumnHeader, ColumnDefinition>();

        private void DataGridTitleSpan_Loaded(object sender, RoutedEventArgs e)
        {
            var hdCols = WPFVisualTreeHelper.GetChildByName<DataGridColumnHeadersPresenter>(this, "PART_ColumnHeadersPresenter");
            var grid = WPFVisualTreeHelper.GetChildByName<Grid>(this, "PART_ColumnHeadersPresenter_Grid");
            if (grid == null)
            {
                return;
            }
            if (DataSouceGridHeaderColTemplate == null || DataSouceGridHeaderColTemplate.Count == 0)
            {
                (grid.Parent as Border).Visibility = Visibility.Collapsed;
                //ColspanVisibility = Visibility.Collapsed;
                return;
            }
            var hdItem = WPFVisualTreeHelper.FindVisualChild<DataGridCellsPanel>(hdCols);
            var header = hdItem.FirstOrDefault();
            if (header != null)
            {
                foreach (var item in header.Children)
                {
                    var vHd = item as DataGridColumnHeader;
                    vHd.SizeChanged += VHd_SizeChanged;
                    ColumnDefinition rd = new ColumnDefinition();
                    rd.Width = new GridLength(vHd.ActualWidth, GridUnitType.Pixel);
                    grid.ColumnDefinitions.Add(rd);
                    dictCols[vHd] = rd;
                }
            }
            GenerateHeader(DataSouceGridHeaderColTemplate, grid);
        }

        private void VHd_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            var vHd = sender as DataGridColumnHeader;
            if (dictCols.ContainsKey(vHd))
            {
                dictCols[vHd].Width = new GridLength(vHd.ActualWidth, GridUnitType.Pixel);
            }
        }


        private void GenerateHeader(List<HeaderTemplate> headers, Grid g)
        {
            int colIndex = 0;
            for (int i = 0; i < headers.Count; i++)
            {
                var col = headers[i];
                g.Children.Add(BigTitle(colIndex, col.ColmunSpan, col.HeaderName));
                colIndex += (col.ColmunSpan + col.ColmunIndex);
            }
        }

        private UIElement BigTitle(int col, int colspan, string text)
        {
            var txb = new TextBlock();
            Border bd = new Border();
            bd.BorderThickness = new Thickness(0, 0, 1, 0);
            bd.BorderBrush = this.BorderBrush;
            //bd.Background = Brushes.Red;
            bd.Child = txb;
            txb.HorizontalAlignment = HorizontalAlignment.Center;
            txb.VerticalAlignment = VerticalAlignment.Center;
            txb.Text = text;
            Grid.SetColumn(bd, col);
            if (colspan > 0)
            {
                Grid.SetColumnSpan(bd, colspan);
            }
            return bd;
        }
    }
}
View Code

如果想修改表格颜色请设置下面三个Brush

  <Setter Property="BorderBrush"
                Value="Blue">
        </Setter>
        <Setter Property="HorizontalGridLinesBrush"
                Value="Blue">
        </Setter>
        <Setter Property="VerticalGridLinesBrush"
                Value="Blue">
        </Setter>
此功能有两个小问题:
1.DataGridTitleSpan_Loaded捕获了DataGrid的列,所以不能在UserControl或者window的Load事件中SetHeaderTemplates,只能再构造函数中设置列。
2.原本以为通过判断合并列的数据如果为空,那么自动隐藏Grid,但是不知道为什么不生效,只能通过依赖属性才能隐藏合并的头
 if (DataSouceGridHeaderColTemplate == null || DataSouceGridHeaderColTemplate.Count == 0)
            {
                (grid.Parent as Border).Visibility = Visibility.Collapsed;
                //ColspanVisibility = Visibility.Collapsed;
                return;
            }

该示例主要的目的通过HeaderTemplate模板数据的配置,实现数表格头部的合并和数据显示。

还有一种稍微复杂表格头的合并,目前是列合并,可能存在行和列同时合并,已经有思路还未验证是否可行,由于项目暂未用到不花费时间研究,园友有需要就在下方留言。

点击此处下载源码

 合并行的已经实现:效果如下

posted @ 2019-01-18 18:54  ligl007  阅读(2475)  评论(2编辑  收藏  举报