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

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

实现思路:

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

 <Grid x:Name="PART_ColumnHeadersPresenter_Grid"
Height=""
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=""
Visibility="{Binding Path=ColspanVisibility,RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}">
<Grid x:Name="PART_ColumnHeadersPresenter_Grid"
Height=""
ShowGridLines="False">
</Grid>
</Border>
<Grid Grid.Row="">
<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=""
d:DesignWidth="">
<UserControl.Resources>
<ResourceDictionary Source="Themes/DataGridStyle.xaml">
</ResourceDictionary>
</UserControl.Resources>
<StackPanel>
<StackPanel Margin="20 15 20 10">
<TextBlock Text="出现滚动条:数据绑定"
Foreground="Red"
FontSize=""></TextBlock>
<local:DataGridTitleSpan x:Name="dataGridTitle2"
Width=""
Height=""
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=""></TextBlock>
<local:DataGridTitleSpan x:Name="dataGridTitle"
Height=""
ScrollViewer.HorizontalScrollBarVisibility="Visible"
ScrollViewer.VerticalScrollBarVisibility="Visible"
DataSouceGridHeaderColTemplate="{Binding Headers0}">
</local:DataGridTitleSpan>
</StackPanel> <StackPanel Margin="20 10">
<TextBlock Text="引用样式"
Foreground="Red"
FontSize=""></TextBlock>
<DataGrid x:Name="dataGrid"
Height=""
Style="{DynamicResource DataGridStyle_Colspan}"
ItemsSource="{Binding DataSource}"
Visibility="Visible">
</DataGrid>
</StackPanel> <StackPanel Margin="20 10">
<TextBlock Text="原生DataGrid"
Foreground="Red"
FontSize=""></TextBlock>
<DataGrid x:Name="dataGrid2"
Height=""
BorderBrush="Blue"
AutoGenerateColumns="False"
HorizontalGridLinesBrush="Blue"
VerticalGridLinesBrush="Blue"
ItemsSource="{Binding DataSource}">
</DataGrid>
</StackPanel>
</StackPanel>
</UserControl>
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 = ;
if (item.ColmunUnitType == "p")
{
unType = DataGridLengthUnitType.Pixel;
width = item.ColmunWidth;
}
else if (item.ColmunUnitType == "s")
{
unType = DataGridLengthUnitType.Star;
width = item.ColmunWidth;
}
if (width < )
{
width = ;
}
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 = , ColmunSpan = , HeaderName = "故障登记时间及状态" });
_headers0.Add(new HeaderTemplate() { ColmunIndex = , ColmunSpan = , HeaderName = "通知时间及通知方法" });
_headers0.Add(new HeaderTemplate() { ColmunIndex = , ColmunSpan = , HeaderName = "到达时间及签名" });
_headers0.Add(new HeaderTemplate() { ColmunIndex = , ColmunSpan = , HeaderName = "消除不良及破损后的时间和方法" }); _headers1.Add(new HeaderTemplate() { ColmunIndex = , ColmunSpan = , PropertyName = "GZDT", PropertyFormat = "MM-dd", ColmunUnitType = "a", ColmunWidth = , HeaderName = "月日" });
_headers1.Add(new HeaderTemplate() { ColmunIndex = , ColmunSpan = , PropertyName = "GZDT", PropertyFormat = "HH:mm", ColmunUnitType = "a", ColmunWidth = , HeaderName = "时分" });
_headers1.Add(new HeaderTemplate() { ColmunIndex = , ColmunSpan = , PropertyName = "GZDeviceName", ColmunUnitType = "a", ColmunWidth = , HeaderName = "设备名称" });
_headers1.Add(new HeaderTemplate() { ColmunIndex = , ColmunSpan = , PropertyName = "GZStatus", ColmunUnitType = "a", ColmunWidth = , HeaderName = "故障状态" }); _headers1.Add(new HeaderTemplate() { ColmunIndex = , ColmunSpan = , PropertyName = "TZDW", ColmunUnitType = "a", ColmunWidth = , HeaderName = "通知单位" });
_headers1.Add(new HeaderTemplate() { ColmunIndex = , ColmunSpan = , PropertyName = "TZDT", PropertyFormat = "MM-dd", ColmunUnitType = "a", ColmunWidth = , HeaderName = "月日" });
_headers1.Add(new HeaderTemplate() { ColmunIndex = , ColmunSpan = , PropertyName = "TZDT", PropertyFormat = "HH:mm", ColmunUnitType = "a", ColmunWidth = , HeaderName = "时分" });
_headers1.Add(new HeaderTemplate() { ColmunIndex = , ColmunSpan = , PropertyName = "TZFF", ColmunUnitType = "a", ColmunWidth = , HeaderName = "通知方法" }); _headers1.Add(new HeaderTemplate() { ColmunIndex = , ColmunSpan = , PropertyName = "DDDT", PropertyFormat = "MM-dd", ColmunUnitType = "a", ColmunWidth = , HeaderName = "月日" });
_headers1.Add(new HeaderTemplate() { ColmunIndex = , ColmunSpan = , PropertyName = "DDDT", PropertyFormat = "HH:mm", ColmunUnitType = "a", ColmunWidth = , HeaderName = "时分" });
_headers1.Add(new HeaderTemplate() { ColmunIndex = , ColmunSpan = , PropertyName = "DDQM", ColmunUnitType = "a", ColmunWidth = , HeaderName = "该段工作人员到达后签名" }); _headers1.Add(new HeaderTemplate() { ColmunIndex = , ColmunSpan = , PropertyName = "BLDT", PropertyFormat = "MM-dd", ColmunUnitType = "a", ColmunWidth = , HeaderName = "月日" });
_headers1.Add(new HeaderTemplate() { ColmunIndex = , ColmunSpan = , PropertyName = "BLDT", PropertyFormat = "HH:mm", ColmunUnitType = "a", ColmunWidth = , HeaderName = "时分" });
_headers1.Add(new HeaderTemplate() { ColmunIndex = , ColmunSpan = , PropertyName = "BLTEXT", ColmunUnitType = "s", ColmunWidth = , HeaderName = "破损及不良的原因,采用何种方法进行\r;修理。工作人员及车站值班员签字" }); for (int i = ; i < ; i++)
{
DataModel model = new DataModel();
model.DDDT = DateTime.Now.AddMinutes(-);
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; }
}
}

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=""
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=""
Grid.Row=""
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=""
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="" />
<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="" />
<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="" />
<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=""
Visibility="{Binding Path=ColspanVisibility,RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}">
<Grid x:Name="PART_ColumnHeadersPresenter_Grid"
Height=""
ShowGridLines="False">
</Grid>
</Border>
<Grid Grid.Row="">
<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="" />
<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="">
<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=""
Grid.Row="" />
<ScrollBar x:Name="PART_VerticalScrollBar"
Grid.Column=""
Maximum="{TemplateBinding ScrollableHeight}"
Orientation="Vertical"
Grid.Row=""
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"
ViewportSize="{TemplateBinding ViewportHeight}" />
<Grid Grid.Column=""
Grid.Row="">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding NonFrozenColumnsViewportHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ScrollBar x:Name="PART_HorizontalScrollBar"
Grid.Column=""
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>
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 == )
{
(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 = ;
for (int i = ; 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(, , , );
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 > )
{
Grid.SetColumnSpan(bd, colspan);
}
return bd;
}
}
}

如果想修改表格颜色请设置下面三个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 == )
{
(grid.Parent as Border).Visibility = Visibility.Collapsed;
//ColspanVisibility = Visibility.Collapsed;
return;
}

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

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

点击此处下载源码

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

WPF DataGridTable的更多相关文章

  1. 在WPF中使用依赖注入的方式创建视图

    在WPF中使用依赖注入的方式创建视图 0x00 问题的产生 互联网时代桌面开发真是越来越少了,很多应用都转到了浏览器端和移动智能终端,相应的软件开发上的新技术应用到桌面开发的文章也很少.我之前主要做W ...

  2. MVVM框架从WPF移植到UWP遇到的问题和解决方法

    MVVM框架从WPF移植到UWP遇到的问题和解决方法 0x00 起因 这几天开始学习UWP了,之前有WPF经验,所以总体感觉还可以,看了一些基础概念和主题,写了几个测试程序,突然想起来了前一段时间在W ...

  3. MVVM模式解析和在WPF中的实现(六) 用依赖注入的方式配置ViewModel并注册消息

    MVVM模式解析和在WPF中的实现(六) 用依赖注入的方式配置ViewModel并注册消息 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二 ...

  4. MVVM模式解析和在WPF中的实现(五)View和ViewModel的通信

    MVVM模式解析和在WPF中的实现(五) View和ViewModel的通信 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 M ...

  5. MVVM设计模式和WPF中的实现(四)事件绑定

    MVVM设计模式和在WPF中的实现(四) 事件绑定 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 MVVM模式解析和在WPF中 ...

  6. MVVM模式解析和在WPF中的实现(三)命令绑定

    MVVM模式解析和在WPF中的实现(三) 命令绑定 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 MVVM模式解析和在WPF中 ...

  7. MVVM模式和在WPF中的实现(二)数据绑定

    MVVM模式解析和在WPF中的实现(二) 数据绑定 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 MVVM模式解析和在WPF中 ...

  8. MVVM模式和在WPF中的实现(一)MVVM模式简介

    MVVM模式解析和在WPF中的实现(一) MVVM模式简介 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 MVVM模式解析和在 ...

  9. 逆天通用水印支持Winform,WPF,Web,WP,Win10。支持位置选择(9个位置 ==》[X])

    常用技能:http://www.cnblogs.com/dunitian/p/4822808.html#skill 逆天博客:http://dnt.dkil.net 逆天通用水印扩展篇~新增剪贴板系列 ...

随机推荐

  1. Python - if-else 的多种简洁写法

    本博客原文来自:http://www.cnblogs.com/xiexiaoxiao/p/7772441.html,对原作者表示感谢,此处个人转载. 1. 常用 if ... else写法 # 语法 ...

  2. Emgu学习之(三)——操作图像数据

    Visual Studio Community 2015 工程和代码:http://pan.baidu.com/s/1jHmlQeE 内容 在这篇文章中将提到以下内容: 修改像素值 图像ROI 图像加 ...

  3. 用ReentrantLock和Condition实现线程间通信

    在Java多线程中,除了使用synchronize关键字来实现线程之间的同步互斥,还可以使用JDK1.5中新增的RetrantLock类来实现同样的效果.RetrantLock类的扩展功能也更加强大, ...

  4. App测试需要测什么

    App,做为当下最热的手机安装软件,无论是产品本身的设计还是性能,易用性等都是非常受考验.一个app能在用户的手机上使用,并作为一个长期用户是非常不容易的.那么,App的测试中我们到底要测试什么呢? ...

  5. Linux 带宽、CPU、内存占用情况

    iftop 查看带宽占用情况(总)yum install -y iftop 安装iftopnethogs 查看进程流量 curl http://218.5.73.233:8060/ip.php 查看出 ...

  6. Reading Meticulous Measurement of Control Packets in SDN

    SOSR 17 概要 网络流量中有一部分是用于网络管理,(根据packet process survey,该部分流量属于包转发的slow path部分)由于sdn的数控分离,交换机需要向控制器发送大量 ...

  7. Linux内核中的jiffies及其作用介绍及jiffies等相关函数详解

    在LINUX的时钟中断中涉及至二个全局变量一个是xtime,它是timeval数据结构变量,另一个则是jiffies,首先看timeval结构struct timeval{time_t tv_sec; ...

  8. Kubernetes(一)--简介

    一.什么是kubernetes(K8s)? Kubernetes作为容器编排生态圈中重要一员,是Google大规模容器管理系统borg的开源版本实现,吸收借鉴了google过去十年间在生产环境上所学到 ...

  9. 【.net开发者自学java系列】使用Eclipse开发SpringMVC(3)

    [.net开发者自学java系列]使用Eclipse开发SpringMVC(3) 标签(空格分隔): Spring RESTful 很久没继续学习java的spring了.接下来继续 回忆一下上个随笔 ...

  10. #leetcode刷题之路21-合并两个有序链表

    将两个有序链表合并为一个新的有序链表并返回.新链表是通过拼接给定的两个链表的所有节点组成的. 示例:输入:1->2->4, 1->3->4输出:1->1->2-&g ...