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
