尊龙凯时网址

基于devexpress的gridcontrol实现的一些界面处理功能 -尊龙凯时网址

2023-08-17,,

devexpress的gridcontrol控件能够提供很多强大的操作,其视图gridview能够通过各种设置,呈现出多种复杂的界面效果,本篇随笔探讨一些常见的gridcontrol控件及其gridview的视图操作处理,以便在大家也需要的时候作为一个参考的代码。其中设计一些常见的操作,如合并单元格、汇总统计、复制粘贴行、导入数据处理、导出excel、导出pdf等、打印gridview视图、内置插入及保存数据处理等等。

1、合并单元格

有时候,需要把多行紧挨着的单元格内容进行合并展示,这样有助于界面的美观及查看便利,如下界面所示。

或者这样的界面,都是类似的效果。

合并的处理比较简单,只需要设置允许合并,以及实现合并的处理事件代码即可。

    //允许合并
this.gridview1.optionsview.allowcellmerge = true;

然后实现的事件代码如下所示。

        private list mergefields = new list { "订单号", "客户订单号", "客户编码", "客户名称", "组合编码", "组合名称"};
private void gridview1_cellmerge(object sender, cellmergeeventargs e)
{
var fieldname = e.column.fieldname;
if(mergefields.contains(fieldname))
{
var view = sender as gridview;
if(view != null)
{
// 获取当前单元格的值
var cellvalue = view.getrowcellvalue(e.rowhandle1, fieldname);
// 获取前一行相同列的单元格的值
var prevcellvalue = view.getrowcellvalue(e.rowhandle2, fieldname); if (e.rowhandle2 >= 0 && cellvalue != null && cellvalue.equals(prevcellvalue))
{
// 合并单元格
e.merge = true;
e.handled = true;
}
}
}
else
{
e.merge = false;
e.handled = true;
}
}

我们可以根据自己的业务需要,设置一些合并的字段,放在列表中即可。呈现的界面效果类似下面所示。

这里值得注意的时候,如果我们需要把列表设置为具有复选框的记录显示模式,方便勾选来进行其他操作,那么就需要取消合并的。

 this.gridview1.optionsview.allowcellmerge = false;

这样才可以进行展示复选框的处理。

2、汇总统计处理

汇总的处理,也是类似的操作,需要设置显示底部的面板,以及设置好汇总列的处理信息。

为了更方便的设置统计信息,我们可以建立一个扩展函数的方式,来实现统计行的信息处理,如下扩展方法所示。

/// 
/// 设置统计列内容
///

/// gridview对象
/// 统计字段
/// 统计类型
/// 显示前缀
public static void setsummarycolumn(this gridview gridview, string fieldname, summaryitemtype summaryitemtype = summaryitemtype.sum,
string prefix = "")
{
if (!gridview.optionsview.showfooter)
{
gridview.optionsview.showfooter = true;
} if (gridview.columns.count > 0)
{
gridview.columns[fieldname].summaryitem.fieldname = fieldname;
gridview.columns[fieldname].summaryitem.displayformat = gridview.columns[fieldname].displayformat.formatstring;
gridview.columns[fieldname].summaryitem.summarytype = summaryitemtype;
gridview.columns[fieldname].summaryitem.displayformat = prefix "{0}";
}
}

如果我们需要在创建统计行的时候,请空它之前的记录信息,那么也可以增加多一个扩展函数来处理清空统计信息,如下所示。

/// 
/// 清空统计项目
///

///
public static void clearsummarycolumns(this gridview gridview)
{
gridview.optionsview.showfooter = false;
foreach (gridcolumn column in gridview.columns)
{
if (column.summaryitem != null)
{
column.summaryitem.collection.clear();
}
}
}

最终我们在界面上创建统计信息的代码如下所示。

    //添加统计行
gridview1.clearsummarycolumns();
gridview1.setsummarycolumn("订单量", devexpress.data.summaryitemtype.sum);
gridview1.setsummarycolumn("完成数量", devexpress.data.summaryitemtype.sum);

最终的界面效果如下所示

3、复制粘贴行及导入处理

有时候为了更加便捷的对记录信息进行复制或者粘贴到gridview列表中进行处理,那么需要设置相关的gridview的属性,让它能够允许复制并设置复制的信息,这样的格式化后,就可以用于粘贴到记事本或者粘贴到新增记录模式下的gridview视图中了。

我们只需要设置其中的optionsclipboard中的某些属性,如下代码所示。

//实现选择复制到新的行中
view.optionsclipboard.allowcopy = defaultboolean.true; //允许复制
view.optionsclipboard.copycolumnheaders = defaultboolean.false; //是否复制表头
view.optionsclipboard.pastemode = devexpress.export.pastemode.append; //粘贴模式
view.optionsclipboard.clipboardmode = devexpress.export.clipboardmode.formatted;//格式化模式

然后,如果我们的gridview是设置到编辑模式的话,设置下面的代码,让它可以新增粘贴的记录。

view.optionsbehavior.editable = true;
view.optionsbehavior.readonly = false;
view.optionsbehavior.allowaddrows = true;

设置好这些,我们如果需要从剪切板中粘贴记录过来,那么只需要简单的饿调用下即可。

view.pastefromclipboard();//从剪切板中复制记录过来

如果需要从excel里面导入到记录表里面我们只需要读取excel里面的记录,然后设置到当前的列表中即可。

var filedialog = new openfiledialog();
filedialog.title = "导入xcel";
filedialog.filter = "excel文件(*.xls)|*.xls";
var dialogresult = filedialog.showdialog(this);
if (dialogresult == dialogresult.ok)
{
excelimporter.importexcel(filedialog.filename, currentview);
}

4、内置的导出excel处理及导出pdf操作

gridview本身控件提供了exporttoxls、exporttoxlsx两个方法,可以直接把数据导出为excel文件,可以指定常规的xls或者xlsx的格式。

如下代码所示。

var filedialog = new savefiledialog();
filedialog.title = "导出excel";
filedialog.filter = "excel文件(*.xls)|*.xls"; var dialogresult = filedialog.showdialog(this);
if (dialogresult == dialogresult.ok)
{
var options = new xlsexportoptions();
options.textexportmode = textexportmode.text; //修改绑定数据的格式为文本
view.exporttoxls(filedialog.filename);
messagedxutil.showtips("导出excel成功!"); if (openexcel && file.exists(filedialog.filename))
{
system.diagnostics.process.start(filedialog.filename);
}
}

当然,我们也可以利用第三方控件aspose.cell或者npoi、myxls的控件进行excel的导出操作,那样也可以提供更多通用的控制处理。

自定义格式的报表导出,可以是一个典型的图文并茂的统计报表,类似样式如下所示。

如我在随笔《使用aspose.cell控件实现excel高难度报表的生成(一)》、《使用aspose.cell控件实现excel高难度报表的生成(二)》、《利用aspose.word控件和aspose.cell控件,实现word文档和excel文档的模板化导出》中介绍过相关的处理方式,一般我们使用封装好的方法,通用的导出excel内容即可,有时候我们直接利用分页控件进行封装,导出常规的excel文档。

asposeexceltools.datatabletoexcel2(table, (string)e.argument, out outerror);

导出excel数据的效果如下所示。

5、打印当前gridview视图

gridview本身也提供了直接打印的操作方法,如果对一些简单的表格,可以直接使用它进行打印当前视图处理。

 currentview.gridcontrol.showribbonprintpreview();

这样的打印效果,呈现出一个ribbon的报表预览界面,然后直接在上面进行定制打印的格式。

或者我们也可以在生成打印预览的时候,指定更多的定制信息,如下界面所示。

private void menu_printfixcolumn_click(object sender, eventargs e)
{
this.wingridviewpager1.gridview1.optionsprint.enableappearanceevenrow = true; using (printablecomponentlink link = new printablecomponentlink(new printingsystem()))
{
link.component = this.wingridviewpager1.gridcontrol1;
link.landscape = true;
link.paperkind = system.drawing.printing.paperkind.a3;
link.createmarginalheaderarea = new createareaeventhandler(link_createmarginalheaderarea);
link.createdocument();
link.showpreview();
}
}
private void link_createmarginalheaderarea(object sender, createareaeventargs e)
{
string title = this.appinfo.appunit " -- " "备件信息报表";
pageinfobrick brick = e.graph.drawpageinfo(pageinfo.none, title, color.darkblue,
new rectanglef(0, 0, 100, 21), borderside.none); brick.linealignment = brickalignment.center;
brick.alignment = brickalignment.center;
brick.autowidth = true;
brick.font = new system.drawing.font("宋体", 11f, fontstyle.bold);
}

类似的打印预览的界面效果如下所示。

当然我们也可以利用第三方控件的打印处理来实现更多的效果,不过内置的gridview打印操作,基本上也能满足大多数的要求了。

6、弹出gridview自定义菜单

gridview的右键菜单,可以用contextmenustrip的常规性菜单控件来定义,我分页控件中就是采用这样的方式,设置比较简单,只需要设置gridctrol控件的contextmenustrip属性即可,如下代码所示。

 this.gridcontrol1.contextmenustrip = this.contextmenustrip1;

并且通过contextmenustrip的opening事件,可以对它进行一定的设置禁用/可用的处理。

 this.contextmenustrip1.opening  = new canceleventhandler(contextmenustrip1_opening);
private void contextmenustrip1_opening(object sender, canceleventargs e)
{
this.menu_add.visible = (this.onaddnew != null && this.showaddmenu);
this.menu_delete.visible = (this.ondeleteselected != null && this.showdeletemenu);
this.menu_edit.visible = (this.oneditselected != null && this.showeditmenu);
this.menu_refresh.visible = (this.onrefresh != null);
}

这样就可以对gridview的右键进行绑定及权限的设置处理,类似下面的界面效果所示。

虽然利用contextmenustrip的传统菜单条,可以很好、方便的实现右键菜单的处理,不过缺点是样式没有随着devexpress本身的效果变化,如果需要追求一样的样式体验,那么可以考虑使用devexpress的popupmenu控件来承载菜单或者ribbon的一些按钮操作。

popupmenu控件可以指定ribbon窗体控件,然后它们右键菜单和ribbon的按钮集合同样的出现和隐藏。

然后在设计模式下设计对应的菜单项目集合。

在界面设计好ribbon的按钮和菜单对象的按钮后,我们可以为菜单绑定对应的gridcontrol事件处理,让它结合gridcontrol的右键事件出现右键菜单。

this.gridcontrol.mouseup  = gridcontrol_mouseup;

显示右键菜单的事件代码如下所示。

private void gridcontrol_mouseup(object sender, mouseeventargs e)
{
try
{
if (e.button == mousebuttons.right)
{
var view = gridcontrol.defaultview as gridview;
var info = view.calchitinfo(e.location);
if (info.inrowcell)
{
popupgridmenu.showpopup(gridcontrol.pointtoscreen(e.location));
}
}
}
catch (exception ex)
{
messagedxutil.showerror(ex.message);
}
}

7、直接新增保存的处理

之前在随笔《在devexpress程序中使用gridview直接录入数据的时候,增加列表选择的功能》 、《在devexpress程序中使用winform分页控件直接录入数据并保存》分别介绍了两种不同方式的数据直接在gridview列表中处理的方式,本质上两者是一致的,都是利用gridview本身的一些事件进行操作,实现更加方便的数据录入体验。

我们一般通过 initnewrow 、validaterow 、cellvaluechanged来处理数据的录入操作,如下详细操作的界面代码所示。

private void registerevent()
{
var grd = this.gridcontrol1;
var grv = this.gridview1;
grv.initgridview(gridtype.newitem, false, editorshowmode.mousedownfocused, "");
//创建显示的列
grv.createcolumn("itemno", "备件编号", 120).createbuttonedit().buttonclick = (s, e) =>
{
#region 选取备件信息,返回后赋值当前记录
if (grv.getfocusedrow() == null)
{
grv.addnewrow();//一定要增加
}
frmselectitemdetail dlg = new frmselectitemdetail();
dlg.warehouse = this.txtwarehouse.text;
if (dlg.showdialog() == system.windows.forms.dialogresult.ok)
{
var info = dlg.itemdetailinfo;
if (info != null)
{
grv.setfocusedrowcellvalue("itemno", info.itemno);
grv.setfocusedrowcellvalue("itemname", info.itemname);
grv.setfocusedrowcellvalue("itembigtype", info.itembigtype);
grv.setfocusedrowcellvalue("itemtype", info.itemtype);
grv.setfocusedrowcellvalue("mapno", info.mapno);
grv.setfocusedrowcellvalue("specification", info.specification);
grv.setfocusedrowcellvalue("unit", info.unit);
grv.setfocusedrowcellvalue("price", info.price);
grv.setfocusedrowcellvalue("material", info.material);
grv.setfocusedrowcellvalue("source", info.source);
grv.setfocusedrowcellvalue("storagepos", info.storagepos);
grv.setfocusedrowcellvalue("usagepos", info.usagepos);
grv.setfocusedrowcellvalue("warehouse", info.warehouse);
grv.setfocusedrowcellvalue("dept", info.dept);
grv.setfocusedrowcellvalue("quantity", 1);//默认数量为1
}
}
#endregion
};
grv.createcolumn("itemname", "备件名称", 120);
grv.createcolumn("quantity", "数量").createspinedit();
grv.createcolumn("itembigtype", "备件属类", 120);
grv.createcolumn("itemtype", "备件类别", 120);
grv.createcolumn("mapno", "图号");
grv.createcolumn("specification", "规格型号", 120);
grv.createcolumn("unit", "单位");
grv.createcolumn("price", "单价");
grv.createcolumn("amount", "金额");
grv.createcolumn("material", "材质", 120);
grv.createcolumn("source", "来源", 120);
grv.createcolumn("storagepos", "库位", 120);
grv.createcolumn("usagepos", "使用位置", 120);
grv.createcolumn("warehouse", "所属库房", 120);
grv.createcolumn("dept", "所属部门", 120); //设置部分字段不可修改
var readonlyfields = "itemname,itembigtype,itemtype,mapno,specification,unit,price,amount,material,source,usagepos,warehouse,dept";
grv.setcolumnsreadonly(readonlyfields); //绑定数据源,否则无法新增存储
var list = new list();
var dt = datatablehelper.converttodatatable(list); //同时增加两列在实体类属性里没有的列
dt.columns.add(new datacolumn("quantity", typeof(int)));
dt.columns.add(new datacolumn("amount", typeof(decimal)));
grd.datasource = dt; grv.initnewrow = delegate(object sender, initnewroweventargs e)
{
//如果是guid的主键,可以初始化,以及赋值明细记录的父id等操作
//gridview gridview = grd.focusedview as gridview;
//gridview.setfocusedrowcellvalue("id", guid.newguid().tostring());
};
grv.validaterow = delegate(object sender, validateroweventargs e)
{
//校验一些不能为空的字段
var result = grd.validaterownull(e, new string[]
{
"itemno",
"itemname",
"quantity"
});
};
grv.cellvaluechanged = (object sender, cellvaluechangedeventargs e) =>
{
//根据数量计算金额
if (e.column.fieldname == "quantity" && e.value != null)
{
var price = string.concat(grv.getfocusedrowcellvalue("price")).todecimal();
var quantity = string.concat(e.value).todecimal();
grv.setfocusedrowcellvalue("amount", price * quantity);
}
};
grv.rowcellstyle = (object sender, rowcellstyleeventargs e) =>
{
//设置特殊颜色标志
if (e.column.fieldname == "quantity" )
{
e.appearance.backcolor = color.moccasin;
e.appearance.forecolor = color.red;
}
};
}

而如果需要结合删除的功能,那么可以增加对rowdeleted的事件处理。

    //行删除操作
grv.optionsbehavior.allowdeleterows = defaultboolean.true;
grv.rowdeleted = (s, ee) =>
{
//同时移除价格列表
var info = ee.row as orderinfo;
if(info != null)
{
this.orderinfos.remove(info);
for (int i = 0; i < this.gridview2.rowcount; i )
{
var code = (string)this.gridview2.getrowcellvalue(i, "产品编码");
if(info.产品编码 == code)
{
this.gridview2.deleterow(i);
}
}
}
};
grv.keydown = (s, ee) =>
{
if (ee.keycode == keys.delete)
{
gridview1.deleteselectedrows();
ee.handled = true;
}
};

以上就是在实际项目中,常用到的gridcontrol和gridview的常规处理方法,用好这些控件的处理,可以极大程度的提高用户的界面体验。

当然可能还有很多常用的方法或者处理方式,等待大家的进一步挖掘和分享。

基于devexpress的gridcontrol实现的一些界面处理功能的相关教程结束。

网站地图