WPF DataGridTable

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

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

实现思路:

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

 "PART_ColumnHeadersPresenter_Grid"
                                  Height="30"
                                  ShowGridLines="False">
                            
   Dictionary dictCols = new Dictionary();

        private void DataGridTitleSpan_Loaded(object sender, RoutedEventArgs e)
        {
            var hdCols = WPFVisualTreeHelper.GetChildByName(this, "PART_ColumnHeadersPresenter");
            var grid = WPFVisualTreeHelper.GetChildByName(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(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列模板

关键代码如下:

显示的View Xaml和Code

"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">
    
        "Themes/DataGridStyle.xaml">
        
    
    
        "20 15 20 10">
            "出现滚动条:数据绑定"
                       Foreground="Red"
                       FontSize="20">
            "dataGridTitle2"
                                       Width="500"
                                       Height="200"
                                       VerticalAlignment="Top"
                                       HorizontalAlignment="Left"
                                       ScrollViewer.HorizontalScrollBarVisibility="Visible"
                                       ScrollViewer.VerticalScrollBarVisibility="Visible"
                                       DataSouceGridHeaderColTemplate="{Binding Headers0}"
                                       ItemsSource="{Binding DataSource}">
            
        
        "20 10">
            "dynamic动态类数据绑定不支持排序"
                       Foreground="Red"
                       FontSize="20">
            "dataGridTitle"
                                       Height="200"
                                       ScrollViewer.HorizontalScrollBarVisibility="Visible"
                                       ScrollViewer.VerticalScrollBarVisibility="Visible"
                                       DataSouceGridHeaderColTemplate="{Binding Headers0}">
            
        

        "20 10">
            "引用样式"
                       Foreground="Red"
                       FontSize="20">
            "dataGrid"
                         Height="200"
                         Style="{DynamicResource DataGridStyle_Colspan}"
                         ItemsSource="{Binding DataSource}"
                         Visibility="Visible">
            
        

        "20 10">
            "原生DataGrid"
                       Foreground="Red"
                       FontSize="20">
            "dataGrid2"
                         Height="200"
                         BorderBrush="Blue"
                         AutoGenerateColumns="False"
                         HorizontalGridLinesBrush="Blue"
                         VerticalGridLinesBrush="Blue"
                         ItemsSource="{Binding DataSource}">
            
        
    
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
{
    /// 
    /// Usr_YunTong46MainView.xaml 的交互逻辑
    /// 
    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 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 _headers0 = new List();
        private List _headers1 = new List();
        private List _dataSource = new List();

        public List Headers0
        {
            get
            {
                return _headers0;
            }

            set
            {
                _headers0 = value;
            }
        }

        public List Headers1
        {
            get
            {
                return _headers1;
            }

            set
            {
                _headers1 = value;
            }
        }

        public List 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; }

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

        public string DDQM { set; get; }

        public DateTime BLDT { set; get; }

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

DataTable样式和Code

"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">
    
    
    "bool2VisibilityConverter" />
    
    
    
    
    
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
{
    /// 
    /// 按照步骤 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 文件中使用控件。
    ///
    ///     
    ///
    /// 
    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 DataSouceGridHeaderColTemplate
        {
            get { return (List)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), 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 dictCols = new Dictionary();

        private void DataGridTitleSpan_Loaded(object sender, RoutedEventArgs e)
        {
            var hdCols = WPFVisualTreeHelper.GetChildByName(this, "PART_ColumnHeadersPresenter");
            var grid = WPFVisualTreeHelper.GetChildByName(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(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 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

  "BorderBrush"
                Value="Blue">
        
        "HorizontalGridLinesBrush"
                Value="Blue">
        
        "VerticalGridLinesBrush"
                Value="Blue">
        
此功能有两个小问题:
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模板数据的配置,实现数表格头部的合并和数据显示。

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

点击此处下载源码

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

你可能感兴趣的:(WPF DataGridTable)