WPF DataGrid table表格强大功能,样式的实现之合计栏

最近准备做几期wpf datagrid优化功能的博客,包括合计栏,标题头带搜索功能,标题头带感叹号的提示框,ui优化等等.本期展示合计栏,后续再添加其他功能代码

1.效果展示

实现wpf datagrid的合计栏,标题头搜索,分页,自定义滚动条, 话不多说 先上效果

合计栏效果展示

在这里插入图片描述

标题头筛选UI还未调整,请忽略

2.合计栏实现流程及代码

(1)重写datagrid样式,在datagrid底部添加一个ItemsControl,用于展示合计的项目同时用ScrollViewer包裹ItemsControl,使之能跟随滚动条滚动
    
        
        
        
        
        
        
        
        
        
        
            
                
                    
                    
                
            
        
        
        
        
        
        
        
        
            
                
                    
                        
                            
                                
                                
                            
                            
                                
                                    
                                        
                                            
                                                
                                                
                                                
                                            
                                            
                                                
                                                
                                                
                                            
                                            
                                                
                                            
                                            
                                            

                                            
                                                
                                                    
                                                    
                                                
                                                
                                            
                                        
                                    
                                
                                
                            
                            
                            
                                
                                    
                                        
                                            
                                                
                                                    
                                                
                                            
                                            
                                                
                                                    
                                                        
                                                    
                                                
                                            
                                        
                                    
                                
                            

                        
                    

                
            
        
        
            
                
                    
                
                
            
        
    

(2)合计栏中每一项宽度的计算

每一项宽度的计算是一个重点,因为每一项的宽度是随内容变化的,同时用户可以拖拽改变每一列的宽度,每次宽度的改变,都得重新计算,这里请注意Border的宽度 Width=“{Binding Width}”,回到cs代码 进行逻辑实现

public static readonly DependencyProperty TotalItemsProperty =
            DependencyProperty.Register("TotalItems", typeof(object), typeof(DataGrid), new PropertyMetadata(null, TotalItemsCallBack));


        public object OriginItemsSource { get; set; }

        public  object ItemsSources
        {
            get { return (object)GetValue(ItemsSourcesProperty); }
            set { SetValue(ItemsSourcesProperty, value); }
        }

以上代码(来自DataGrid自定义样式类)是合计栏的数据来源,是一个对象,通过后端接口返回的,当然,也可以由前端自己合计,对TotalItems进行赋值即可,赋值方式如下(来自ViewModel业务代码)

在这里插入图片描述

(3)TotalItemsCallBack(合计项赋值后回调)代码分析
        private static void TotalItemsCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataGrid dataGrid = d as DataGrid;
            if (e.NewValue != null && dataGrid.itemsControl != null)
            {
                if (e.NewValue is List totalItems)
                {
                    //数组和对象都要转为数组;
                    //排序问题处理
                    System.Threading.Tasks.Task.Factory.StartNew(() =>
                    {
                        System.Threading.Thread.Sleep(1000);
                        Application.Current.Dispatcher.BeginInvoke((Action)(() =>
                        {
                            List dataGrids = new List();
                            for (int i = 0; i < dataGrid.Columns.Count; i++)
                            {
                                if (dataGrid.Columns[i].Visibility == Visibility.Visible)
                                {
                                    if (totalItems != null && totalItems.Count >= i + 1 && totalItems[i] != null)
                                    {
                                        dataGrids.Add(new DataGridTotal { Width = dataGrid.Columns[i].ActualWidth, Content = totalItems[i], Index = dataGrid.Columns[i].DisplayIndex });
                                    }
                                    else
                                    {
                                        dataGrids.Add(new DataGridTotal { Width = dataGrid.Columns[i].ActualWidth, Content = "-", Index = dataGrid.Columns[i].DisplayIndex });
                                    }

                                }
                            }
                            dataGrids = dataGrids.OrderBy(x => x.Index).ToList();
                            dataGrid.itemsControl.ItemsSource = dataGrids;
                        }));
                    });
                }
                else if(e.NewValue is object obj){
                    System.Threading.Tasks.Task.Factory.StartNew(() =>
                    {
                        System.Threading.Thread.Sleep(1000);
                        Application.Current.Dispatcher.BeginInvoke((Action)(() =>
                        {
                            List dataGrids = new List();
                            for (int i = 0; i < dataGrid.Columns.Count; i++)
                            {
                                if (dataGrid.Columns[i].Visibility == Visibility.Visible)
                                {
                                    var content = "-";
                                    if (obj.GetType().GetProperty(dataGrid.Columns[i].SortMemberPath) != null)
                                    {
                                        content = obj.GetType().GetProperty(dataGrid.Columns[i].SortMemberPath).GetValue(obj, null)?.ToString();
                                    }
                                    dataGrids.Add(new DataGridTotal { Width = dataGrid.Columns[i].ActualWidth, Content = string.IsNullOrEmpty(content) ? "-" : content, Index = dataGrid.Columns[i].DisplayIndex });

                                }
                            }
                            dataGrids = dataGrids.OrderBy(x => x.Index).ToList();
                            dataGrid.itemsControl.ItemsSource = dataGrids;
                        }));
                    });
                }
            }
            else {
                System.Threading.Tasks.Task.Factory.StartNew(() => {
                    System.Threading.Thread.Sleep(1000);
                    Application.Current.Dispatcher.BeginInvoke((Action)(() =>
                    {
                        List dataGrids = new List();
                        for (int i = 0; i < dataGrid.Columns.Count; i++)
                        {
                            if (dataGrid.Columns[i].Visibility == Visibility.Visible)
                            {
                                dataGrids.Add(new DataGridTotal { Width = dataGrid.Columns[i].ActualWidth, Content = "-", Index = dataGrid.Columns[i].DisplayIndex });
                            }
                        }
                        dataGrids = dataGrids.OrderBy(x => x.Index).ToList();
                        dataGrid.itemsControl.ItemsSource = dataGrids;
                    }));
                });
            }
        }

TotalItems赋值时可以是数组,也可以是对象,数组的话需要按照顺序从左到右一次返回;

Width = dataGrid.Columns[i].ActualWidth是宽度的首次计算;

Index = dataGrid.Columns[i].DisplayIndex 是排序的顺序,确保合计的项不会错位;

DataGridTotal类如下:

public class DataGridTotal
    {
        /// 
        /// 内容
        /// 
        public string Content { get; set; }
        /// 
        /// 宽度
        /// 
        public double Width { get; set; }
        /// 
        /// 排序
        /// 
        public int Index { get; set; } 
        /// 
        /// 标题头
        /// 
        public string Header { get; set; }
    }

加入异步是为了减少前端自己合计 数据量大时的卡顿效果

(4)用户拖动标题头,顺序发生改变后逻辑处理

对合计栏的排序进行重新计算

        private void DataGrid_ColumnDisplayIndexChanged(object sender, DataGridColumnEventArgs e)
        {
            if (TotalItems != null)
            {
                List dataGrids = new List();

                if (TotalItems is List items)
                {
                    for (int i = 0; i < Columns.Count; i++)
                    {
                        if (Columns[i].Visibility == Visibility.Visible)
                        {
                            dataGrids.Add(new DataGridTotal { Width = Columns[i].ActualWidth, Content = items[i], Index = Columns[i].DisplayIndex });
                        }
                    }
                }
                else if(TotalItems is object obj)
                {
                    for (int i = 0; i < Columns.Count; i++)
                    {
                        if (Columns[i].Visibility == Visibility.Visible)
                        {
                            var content = "-";
                            if (obj.GetType().GetProperty(Columns[i].SortMemberPath) != null)
                            {
                                content = obj.GetType().GetProperty(Columns[i].SortMemberPath).GetValue(obj, null)?.ToString();
                            }
                            dataGrids.Add(new DataGridTotal { Width = Columns[i].ActualWidth, Content = string.IsNullOrEmpty(content)?"-":content, Index = Columns[i].DisplayIndex });
                        }
                    }
                    
                }

                
                dataGrids = dataGrids.OrderBy(x => x.Index).ToList();
                itemsControl.ItemsSource = dataGrids;
            }
            else {
                List dataGrids = new List();
                for (int i = 0; i < Columns.Count; i++)
                {
                    if (Columns[i].Visibility == Visibility.Visible)
                    {
                        dataGrids.Add(new DataGridTotal { Width = Columns[i].ActualWidth, Content = "-", Index = Columns[i].DisplayIndex });
                    }
                }
                dataGrids = dataGrids.OrderBy(x => x.Index).ToList();
                itemsControl.ItemsSource = dataGrids;
            }
            
        }

(5)合计栏宽度自适应

内容发生改变,列宽自动撑开后合计栏宽度的自适应,用户拖动列的宽度后,合计栏的自适应

private void OwnScrrow_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            /*
            Console.WriteLine("----------------------------");
            Console.WriteLine("ScrollableWidth:"+ownScrrow.ScrollableWidth);
            Console.WriteLine("ExtentWidth:"+ownScrrow.ExtentWidth);
            Console.WriteLine("VerticalOffset:" + ownScrrow.VerticalOffset);
            Console.WriteLine("HorizontalOffset:" + ownScrrow.HorizontalOffset);
            */
            DataGrid_ColumnDisplayIndexChanged(null, null);

            /*
            if (ownScrrow.ScrollableWidth != horOffset)
            {
                horOffset = ownScrrow.ScrollableWidth;
                //宽度发生改变 通知滚动条重新渲染
                Console.WriteLine(horOffset);
                DataGrid_ColumnDisplayIndexChanged(null, null);
            } 
            */
            scrollViewer.ScrollToHorizontalOffset((sender as ScrollViewer).HorizontalOffset);
        }

3.性能分析

windows xp(客户那里找来的,估计年龄比我还大) 256m内存运行流畅,高于此配置均能完美运行

4.代码

gitee地址

本文来自网络,不代表协通编程立场,如若转载,请注明出处:https://www.net2asp.com/bee94880cd.html