在做wpf开发的时候,经常会遇到需要展示表格数据的场景。大家最熟悉的可能是datagrid控件,它用起来方便,绑定数据简单。
但有个问题一直困扰着我:当表格的列数不固定,需要根据数据动态变化时,datagrid就显得有些力不从心了。
最近在做一个项目时,正好遇到了这样的需求——要根据测量数据动态生成行列可变的表格,经过一番摸索,最终用grid控件从后台代码实现了这个功能,效果还不错,今天就来分享一下。
前言
项目背景是这样的:我们需要展示一组宽度测量数据,每组数据包含多个边缘的振幅值,而不同组的边缘数量是不一样的。如果用传统的datagrid,列数固定,很难灵活展示这种数据结构。
于是,我决定放弃datagrid,转而使用grid控件,通过代码动态生成表格。
效果演示
从图中可以看到,表格的列数是根据数据动态生成的,每组数据的边缘数量不同,表格的列数也随之变化,而且每组数据之间有明显的分隔,整体效果清晰明了。
实现方法
先看前台xaml部分:
<dxlc:layoutcontrol>
<grid horizontalalignment="left" verticalalignment="top"
cal:message.attach="[event loaded]=[grid_loaded($source,$eventargs)]" />
</dxlc:layoutcontrol>
我把grid放在了dxlc:layoutcontrol中,这样当表格尺寸超出界面分配的长宽时,会自动出现滚动条,用户体验更好。
再来看后台代码。首先定义数据模型:
public class widthmetrologydto
{
public bool ismeasuresuccess { get; set; }
public double degree { get; set; }
public string imagefilepath { get; set; }
public double width { get; set; }
public double edgenum { get; set; }
public list<edgeposition> edgepositions { get; set; }
}
public class edgeposition
{
public double edgesamplitude { get; set; }
}
然后在代码中定义grid和数据集合:
public grid resultdisplaygrid;
public bindablecollection<widthmetrologydto> widthmetrologydata { get; set; }
= new bindablecollection<widthmetrologydto>();
在grid加载时获取grid对象:
public void grid_loaded(object sender, routedeventargs e)
{
resultdisplaygrid = (grid)sender;
}
接着添加一些测试数据:
public void resultdispaly()
{
try
{
widthmetrologydata.clear();
widthmetrologydata.add(new widthmetrologydto
{
width = 345.1,
edgenum = 3,
edgepositions = new list<edgeposition>
{
new edgeposition(){edgesamplitude = 1.1},
new edgeposition(){edgesamplitude = 2.2},
new edgeposition(){edgesamplitude = 3.3},
},
});
widthmetrologydata.add(new widthmetrologydto
{
width = 345.2,
edgenum = 2,
edgepositions = new list<edgeposition>
{
new edgeposition(){edgesamplitude = 4.4},
new edgeposition(){edgesamplitude = 5.5},
},
});
widthmetrologydata.add(new widthmetrologydto
{
width = 345.3,
edgenum = 4,
edgepositions = new list<edgeposition>
{
new edgeposition(){edgesamplitude = 6.6},
new edgeposition(){edgesamplitude = 7.7},
new edgeposition(){edgesamplitude = 8.8},
new edgeposition(){edgesamplitude = 9.9},
},
});
widthmetrologydata.add(new widthmetrologydto
{
width = 345.0,
edgenum = 1,
edgepositions = new list<edgeposition>
{
new edgeposition(){edgesamplitude = 0.66},
},
});
addresultgrid();
}
catch (exception ex)
{
//logger.debug($"resultdata add fail : {ex}");
}
}
最后是生成表格的核心代码:
public void addresultgrid()
{
try
{
resultdisplaygrid.children.clear();
var gridcolumns = 2 + widthmetrologydata.orderbydescending(index => index.edgepositions.count).firstordefault().edgepositions.count;
var gridrows = 16;
//添加grid行
for (int i = 0; i < gridcolumns; i++)
{
var columndefinition = new columndefinition();
resultdisplaygrid.columndefinitions.add(columndefinition);
if (i == 1)
{
columndefinition.width = new gridlength(2, gridunittype.star);//相对尺寸
}
else
{
columndefinition.width = new gridlength(1, gridunittype.star);
}
//columndefinition.width = gridlength.auto;
}
//添加grid列
for (int i = 0; i < gridrows; i++)
{
var rowdefinition = new rowdefinition();
resultdisplaygrid.rowdefinitions.add(rowdefinition);
rowdefinition.height = new gridlength(30, gridunittype.pixel);//绝对尺寸
}
//添加数据
//var controlwidth = 100;
//var controlheight = 30;
for (int degreeindex = 0; degreeindex < widthmetrologydata.count; degreeindex++)
{
var rowscount = 3;
var columnscount = widthmetrologydata[degreeindex].edgepositions.count;
for (int row = 0; row < rowscount; row++)
for (int column = 0; column < columnscount + 2; column++)
{
textblock tb = new textblock();
//tb.width = controlwidth;
//tb.height = controlheight;
//tb.horizontalalignment = horizontalalignment.left;
//tb.verticalalignment = verticalalignment.center;
border border = new border();
border.borderbrush = system.windows.media.brushes.blueviolet;
border.borderthickness = new thickness(1);
border.child = tb;
border.setvalue(grid.rowproperty, row + degreeindex * 4);
border.setvalue(grid.columnproperty, column);
resultdisplaygrid.children.add(border);
if (row == 0 && column >= 2)
{
tb.text = (column - 1).tostring();
}
else if (row == 1 && column >= 2)
{
tb.text = widthmetrologydata[degreeindex].edgepositions[column - 2].edgesamplitude.tostring();
}
else if (row == 2 && column >= 2)
{
if (column == 2)
{
tb.text = widthmetrologydata[degreeindex].width.tostring();
//tb.width = columnscount * controlwidth;
tb.setvalue(grid.columnspanproperty, columnscount);
}
else
{
continue;
}
}
if (column == 0)
{
if (row == 0)
{
switch (degreeindex)
{
case 0:
tb.text = "第一组"; break;
case 1:
tb.text = "第二组"; break;
case 2:
tb.text = "第三组"; break;
case 3:
tb.text = "第四组"; break;
default: break;
}
//tb.height = 3 * controlheight;
tb.setvalue(grid.rowspanproperty, 3);
}
else
{
continue;
}
}
if (column == 1)
{
switch (row)
{
case 0:
tb.text = "id"; break;
case 1:
tb.text = "value"; break;
case 2:
tb.text = "fraction"; break;
default:
tb.text = string.empty; break;
}
//tb.width = controlwidth;
}
}
}
resultdisplaygrid.width = (gridcolumns + 1)* 40;
//resultdisplaygrid.height = gridrows * controlheight;
}
catch (exception ex)
{
//logger.error($"add result grid fail,{ex}");
}
}
总结
通过这次实践,我发现用grid控件从后台代码生成表格,虽然代码量比用datagrid多一些,但灵活性大大增强。特别是当表格结构需要根据数据动态变化时,这种方法显得尤为实用。关键是要理清数据结构,合理规划grid的行列布局,再通过代码动态生成控件并设置其位置。虽然过程有点繁琐,但最终的效果让人满意。
到此这篇关于wpf动态生成行列可变表格的实现方法详解的文章就介绍到这了,更多相关wpf生成行列可变表格内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论