有時(shí)候聽有些朋友抱怨.net的datagrid不是很好用。就我個(gè)人的體會,datagrid的功能非常強(qiáng)大,可以使我們隨心所欲的完成各種各樣的工作,可惜就是實(shí)現(xiàn)起來不夠簡單明了。我對平時(shí)經(jīng)常碰到的一些問題積累了一些解決的方法,現(xiàn)在把它們總結(jié)一下供大家參考。
比較經(jīng)常碰到的一個(gè)問題是:我們希望datagrid的某一列只能輸入特定的文本,比如:不能輸入數(shù)字。下面的例子說明如何實(shí)現(xiàn)這種功能。
新建一個(gè)window應(yīng)用程序,加入一個(gè)datagrid和sqlconnection,連接sql數(shù)據(jù)庫northwind。
namespace windowsapplication1
{
public class form1 : system.windows.forms.form
{
private mydatagrid datagrid1;
private system.data.sqlclient.sqlconnection sqlconnection1;
//加入全局變量oldvalue,用它表示單元格原來的文本。
private string oldvalue;
private void form1_load(object sender, system.eventargs e)
{
oldvalue="";
sqldataadapter sda=new sqldataadapter("select lastname,firstname from employees",this.sqlconnection1);
dataset ds=new dataset();
sda.fill(ds,"employees");
datagridtablestyle ats=new datagridtablestyle();
ats.mappingname="employees";
datagridcolorcolumn dcs1=new datagridcolorcolumn();
dcs1.headertext="lastname";
ats.gridcolumnstyles.add(dcs1);
datagridtextboxcolumn dcs2=new datagridtextboxcolumn();
dcs2.headertext="firstname";
dcs2.mappingname="firstname";
dcs2.textbox.textchanged+=new eventhandler(datagridtextchanged);
dcs2.textbox.enter+=new eventhandler(datagridtextbox_enter);
ats.gridcolumnstyles.add(dcs2);
this.datagrid1.tablestyles.add(ats);
this.datagrid1.datasource=ds;
this.datagrid1.datamember="employees";
}
private void datagridtextbox_enter(object sender,eventargs e)
{
//當(dāng)某一單元格獲得焦點(diǎn)時(shí),記錄單元格的文本
oldvalue=((datagridtextboxcolumn) this.datagrid1.tablestyles[0].gridcolumnstyles[1]).textbox.text;
}
private void datagridtextchanged(object sender,eventargs e)
{
int index=0;
string str=((datagridtextboxcolumn)this.datagrid1.tablestyles[0].gridcolumnstyles[1]).textbox.text;
//當(dāng)單元格的文本改變時(shí),檢驗(yàn)是否有非法字符
while(index<str.length)
{
//如果發(fā)現(xiàn)數(shù)字,顯示錯(cuò)誤信息并將單元格還原為原內(nèi)容
if (char.isdigit(str,index))
{
messagebox.show("不能輸入數(shù)字,請重新輸入");
((datagridtextboxcolumn)this.datagrid1.tablestyles[0].gridcolumnstyles[1]).textbox.text=oldvalue;
return;
}
index++;
}
}
}
------------如何實(shí)現(xiàn)多行表頭
有時(shí)候聽有些朋友抱怨.net的datagrid不是很好用。就我個(gè)人的體會,datagrid的功能非常強(qiáng)大,可以使我們隨心所欲的完成各種各樣的工作,可惜就是實(shí)現(xiàn)起來不夠簡單明了。我對平時(shí)經(jīng)常碰到的一些問題積累了一些解決的方法,現(xiàn)在把它們總結(jié)一下供大家參考。
比較經(jīng)常碰到的一個(gè)問題是:我們希望datagrid的表頭是多行的(圖1)。我在網(wǎng)上找了很久也找不到解決的方法,后來想到了datagrid的captiontext和captionfont屬性。于是我就想能不能在caption的顯示區(qū)域畫出多行表頭。下面的示例代碼實(shí)現(xiàn)了這個(gè)想法,結(jié)果如圖1所示。
首先需要編寫一個(gè)類來表示自畫的表頭,這個(gè)類將記錄表頭的顯示文本、圖標(biāo)和屬于它管轄的列的信息。
//表頭類
public class topheadercolumn
{
public topheadercolumn()
{
this.columncollection=new arraylist();
}
private string caption;
//表頭的顯示文本
public string caption
{
get {return caption;}
set {caption=value;}
}
private arraylist columncollection;
//用來記錄屬于表頭管轄的各列的信息(通過往集合里添加object)
public arraylist columncollection
{
get {return this.columncollection;}
set {this.columncollection=value;}
}
private int width;
//表頭的寬度
public int width
{
get {return width;}
set {width=value;}
}
private image image=null;
//表頭的圖標(biāo)
public image image
{
get {return image;}
set {image=value;}
}
}
另外,因?yàn)橐院蟮拇a需要datagrid水平滾動條的位置,而datagrid無法取得水平滾動條的位置,所以需要對datagrid做一點(diǎn)修改。
public class mydatagrid:datagrid
{
public scrollbar hscrollbar
{
get {return this.horizscrollbar;}
}
}
好了,可以工作了。新建一個(gè)window應(yīng)用程序,加入一個(gè)mydatagrid、sqlconnection和imagelist,連接sql數(shù)據(jù)庫northwind。當(dāng)然,還得加入上面的代碼
namespace windowsapplication1
{
public class form1 : system.windows.forms.form
{
private system.data.sqlclient.sqlconnection sqlconnection1;
private mydatagrid datagrid1;
private arraylist al;
private system.windows.forms.imagelist imagelist1;
//在initializecomponent()里加入這一句:this.datagrid1 = new mydatagrid(),并根據(jù)你的需要設(shè)置其他的datagrid屬性。注意,captionvisible必須設(shè)為true,captiontext=""。
private void form1_load(object sender, system.eventargs e)
{
sqldataadapter da=new sqldataadapter("select lastname, firstname, address,city from employees",this.sqlconnection1);
dataset ds=new dataset();
da.fill(ds,"employees");
this.datagrid1.datasource=ds;
this.datagrid1.datamember="employees";
//設(shè)置datagrid的各列
datagridtextboxcolumn c1=new datagridtextboxcolumn();
datagridtextboxcolumn c2=new datagridtextboxcolumn();
datagridtextboxcolumn c3=new datagridtextboxcolumn();
datagridtextboxcolumn c4=new datagridtextboxcolumn();
c1.mappingname="lastname";
c2.mappingname="firstname";
c3.mappingname="address";
c4.mappingname="city";
c1.headertext="lastname";
c2.headertext="firstname";
c3.headertext="address";
c4.headertext="city";
c1.widthchanged+=new eventhandler(this.abc);//列的寬變動時(shí)調(diào)整表頭寬度
c2.widthchanged+=new eventhandler(this.abc);
c3.widthchanged+=new eventhandler(this.abc);
c4.widthchanged+=new eventhandler(this.abc);
datagridtablestyle dts=new datagridtablestyle();
dts.gridcolumnstyles.add(c1);
dts.gridcolumnstyles.add(c2);
dts.gridcolumnstyles.add(c3);
dts.gridcolumnstyles.add(c4);
dts.mappingname="employees"; this.datagrid1.tablestyles.add(dts);
//建立自畫的表頭類并將它們加入集合al
al=new arraylist();
topheadercolumn tc1=new topheadercolumn();
tc1.caption="name";
tc1.image=this.imagelist1.images[0];
tc1.columncollection.add(0);//記錄它管轄的列的index
tc1.columncollection.add(1);
tc1.width=c1.width+c2.width;
topheadercolumn tc2=new topheadercolumn();
tc2.caption="address";
tc2.columncollection.add(2);
tc2.columncollection.add(3);
tc2.width=c3.width+c4.width;
al.add(tc1);
al.add(tc2);
this.datagrid1.paint += new system.windows.forms.painteventhandler(this.datagrid1_paint);
}
private void datagrid1_paint(object sender, system.windows.forms. painteventargs e)
{
int x=0;
//計(jì)算出第一個(gè)表頭的左邊距
int left=this.datagrid1.tablestyles[0].rowheaderwidth-this.datagrid1.hscrollbar.value;
//遍歷表頭集合al,畫出表頭
foreach (object o in this.al)
{
//計(jì)算出表頭文字(文字居中)的左邊距
x=left+(((topheadercolumn)o).width-convert.toint32(e.graphics. measurestring (((topheadercolumn)o).caption, this.datagrid1.captionfont). width))/2;
//完成表頭繪制
if (((topheadercolumn)o).image!=null)
e.graphics.drawimage(((topheadercolumn)o).image,x-imagelist1.images[0].size.width,0);
e.graphics.drawstring(((topheadercolumn)o).caption,this.datagrid1. captionfont,new solidbrush(this.datagrid1.captionforecolor),x,0);
if (x>0)
e.graphics.drawline(new pen(color.black,2),left-1,0,left-1,this.datagrid1.height);
//計(jì)算出下一個(gè)表頭的左邊距
left+=((topheadercolumn)o).width;
}
if (x<this.datagrid1.width)
e.graphics.drawline(new pen(color.black,2),left-1,0,left-1,this.datagrid1.height);
}
private void abc(object sender,eventargs e)
{
//設(shè)置表頭的寬度
foreach (object o in this.al)
{
((topheadercolumn)o).width=0;
foreach (int i in ((topheadercolumn)o).columncollection)
{ ((topheadercolumn)o).width+=this.datagrid1.tablestyles[0].gridcolumnstyles[i].width;
}
}
}
private void datagrid1_scroll(object sender, system.eventargs e)
{
this.datagrid1.refresh();
}
上面的代碼實(shí)現(xiàn)了兩層表頭,至于三層表頭也同理。
關(guān)于如何實(shí)現(xiàn)datagrid多層表頭,許多網(wǎng)友都提到,目前好像沒有一種特別好的方便的方法。
--------如何實(shí)現(xiàn)下拉列表
有時(shí)候聽有些朋友抱怨.net的datagrid不是很好用。就我個(gè)人的體會,datagrid的功能非常強(qiáng)大,可以使我們隨心所欲的完成各種各樣的工作,可惜就是實(shí)現(xiàn)起來不夠簡單明了。我對平時(shí)經(jīng)常碰到的一些問題積累了一些解決的方法,現(xiàn)在把它們總結(jié)一下供大家參考。
比較經(jīng)常碰到的一個(gè)問題是:在編輯單元格內(nèi)容時(shí)我們希望出現(xiàn)這樣的下拉列表,如圖1所示:
圖1
思路:
1 寫一個(gè)類comboform表示下拉列表,類包含兩個(gè)成員:form窗體和datagrid組件。
2 寫一個(gè)類nokeyupcombobox(繼承combobox),目的是屏蔽wm_keyup消息,避免在按tab鍵時(shí)出現(xiàn)問題。
3 寫一個(gè)繼承于datagridtextboxcolumn的類,命名為datagridcomboformcolumn。在類中加入一個(gè)combobox和一個(gè)comboform,類實(shí)現(xiàn)下面幾個(gè)功能:
a 編輯單元格內(nèi)容時(shí)顯示組件nokeyupcombobox;
b combobox下拉時(shí)顯示下拉列表comboform;
c 鼠標(biāo)點(diǎn)擊下拉列表時(shí),隱藏comboform并將用戶選定的內(nèi)容寫入單元格(當(dāng)然,你也可以設(shè)置其他隱藏下拉列表的操作,比如按回車鍵);
d 下拉列表comboform不具有焦點(diǎn)時(shí)隱藏。
代碼:
//comboform類:
public class comboform:form
{
private datagrid datagrid;
public datagrid datagrid
{
get {return datagrid;}
set {datagrid=value;}
}
public comboform()
{
this.formborderstyle=formborderstyle.none;
this.startposition=formstartposition.manual;
datagrid=new datagrid();
this.controls.add(datagrid);
datagrid.dock=dockstyle.fill;
datagrid.captionvisible=false;
}
}
//nokeyupcombobox類:
public class nokeyupcombobox:combobox
{
const int wm_keyup=0x101;
protected override void wndproc(ref message msg)
{
if (msg.msg==wm_keyup)
return;
base.wndproc(ref msg);
}
}
//datagridcomboformcolumn類:
public class datagridcomboformcolumn:datagridtextboxcolumn
{
private nokeyupcombobox combobox;
private currencymanager _source;
private int rownum;
private comboform frm;
public comboform frm
{
get {return frm;}
}
//我們將使用index屬性表示單元格內(nèi)容與下拉列表的第index列的內(nèi)容相聯(lián)系
private int index;
public int index
{
get {return index;}
set {index=value;}
}
public datagridcomboformcolumn()
{
frm=new comboform();
combobox=new nokeyupcombobox();
frm.deactivate+=new eventhandler(frm_deactive);
frm.datagrid.click+=new eventhandler(grid_click);
this.combobox.dropdown+=new eventhandler(combobox_dropdown);
this.combobox.leave+=new eventhandler(combobox_leave);
}
//combobox不具有焦點(diǎn)時(shí)隱藏
private void combobox_leave(object sender,eventargs e)
{
combobox.visible=false;
}
//下拉列表--frm不具有焦點(diǎn)時(shí)隱藏
private void frm_deactive(object sender,eventargs e)
{
frm.hide();
combobox.visible=false;
}
//combobox下拉時(shí)顯示下拉列表--frm
private void combobox_dropdown(object sender,eventargs e)
{
//在這里您還可以根據(jù)下拉列表的長與寬是否超出屏幕設(shè)置下拉列表的位置
frm.left=combobox.pointtoscreen(new point(0,combobox.height)).x;
frm.top=combobox.pointtoscreen(new point(0,combobox.height)).y;
frm.show();
frm.bringtofront();
}
//點(diǎn)擊下拉列表的datagrid時(shí),將選中的內(nèi)容寫入單元格并隱藏下拉列表--frm
private void grid_click(object sender,eventargs e)
{
bindingmanagerbase cm=frm.bindingcontext[frm.datagrid.datasource, frm.datagrid.datamember];
combobox.text=((datarowview)cm.current)[index].tostring();
this.textbox.text=((datarowview)cm.current)[index].tostring();
frm.hide();
combobox.visible=false;
this.setcolumnvalueatrow(_source,rownum,this.textbox.text);
}
//重載edit方法,使用combobox代替textbox
protected override void edit(currencymanager datasource,int rownum,rectangle bounds,bool readonly,string instanttext,bool cellvisible)
{
base.edit(datasource,rownum,bounds,readonly,instanttext,cellvisible);
combobox.parent=this.textbox.parent;
combobox.left=this.textbox.left-2;
combobox.top=this.textbox.top-2;
combobox.size=new size(this.textbox.width,this.combobox.height);
combobox.text=this.textbox.text;
this.textbox.visible=false;
combobox.visible=true;
combobox.bringtofront();
combobox.focus();
_source=datasource;
this.rownum=rownum;
}
}
下面的例子說明了如何使用datagridcombofrom類:
新建一個(gè)windows 應(yīng)用程序,加入sqlconnection,連接sql數(shù)據(jù)庫northwind,加入下面代碼。
private void form1_load(object sender, system.eventargs e)
{
sqldataadapter da=new sqldataadapter("select productname from products",this.sqlconnection1);
dataset ds=new dataset();
da.fill(ds,"products");
dataset ds_combo=new dataset();
da.selectcommand=new sqlcommand("select productname,quantityperunit,unitprice from products",this.sqlconnection1);
da.fill(ds_combo,"products");
datagridtablestyle dts=new datagridtablestyle();
dts.mappingname="products";
mydatagridcolumn col=new mydatagridcolumn();
col.mappingname="productname";
col.width=100;
col.index=0;
col.headertext="productname";
col.frm.datagrid.datasource=ds_combo;//設(shè)置下拉列表的數(shù)據(jù)源
col.frm.datagrid.datamember="products";
dts.gridcolumnstyles.add(col);
this.datagrid1.tablestyles.add(dts);
this.datagrid1.setdatabinding(ds,"products");
}
------------如何在datagrid中顯示來自不同datatable的數(shù)據(jù)
有時(shí)候聽有些朋友抱怨.net的datagrid不是很好用。就我個(gè)人的體會,datagrid的功能非常強(qiáng)大,可以使我們隨心所欲的完成各種各樣的工作,可惜就是實(shí)現(xiàn)起來不夠簡單明了。我對平時(shí)經(jīng)常碰到的一些問題積累了一些解決的方法,現(xiàn)在把它們總結(jié)一下供大家參考。
比較經(jīng)常碰到的一個(gè)問題是:如何將來自不同datatable的字段組合顯示在datagrid中?當(dāng)然,可以將數(shù)據(jù)合并到一個(gè)datatable中,但有時(shí)候由于其他限制不能將數(shù)據(jù)合并,下面提供了一種在datagrid中顯示來自不同datatable(同在一個(gè)dataset中)的數(shù)據(jù)的方法。
數(shù)據(jù)在dataset中的結(jié)構(gòu)
我們希望數(shù)據(jù)在datagrid中如下圖顯示
下面用一個(gè)例子說明如何實(shí)現(xiàn)將來自不同datatable的數(shù)據(jù)顯示在datagrid中。
基本思路:很顯然,datagrid不能同時(shí)綁定兩個(gè)datatable,那么,要使它顯示兩個(gè)不同datatable的數(shù)據(jù),就只有在datagridcolumn中下功夫了。以上面的結(jié)構(gòu)為例,我們建立一個(gè)繼承datagridtextboxcolumn的類datagridjoincolumn,重載getcolumnvalueatrow方法。這個(gè)類要實(shí)現(xiàn)的功能是:數(shù)據(jù)源是datatable1,返回值是datatable1.employeeid對應(yīng)的datatable2.lastname或datatable2.firstname。datatable1.employeeid與datatable2.employeeid是1對多聯(lián)系,我們將這個(gè)聯(lián)系添加到dataset中,就可以通過getparentrow(relation)方法取得datatable1.employeeid對應(yīng)的datatable2.lastname和datatable2.firstname的值。具體代碼如下:
public class jointextboxcolumn : datagridtextboxcolumn
{
string relation; //表示datatable1.employeeid與datatable2.employeeid的1對多聯(lián)系
datacolumn col; //表示返回datatable2的列
public jointextboxcolumn(string relation,datacolumn col )
{
this.relation=relation;
this.col=col;
base.readonly=true;
}
protected override object getcolumnvalueatrow(currencymanager cm,int rownum)
{
try
{
datarow dr=((dataview)cm.list)[rownum].row;
datarow parentdr=dr.getparentrow(relation);
return parentdr[col]; //返回值是datatable1.employeeid對應(yīng)的lastname或firstname
}
catch
{
return ""; //避免在添加新行時(shí)發(fā)生異常
}
}
protected override bool commit(currencymanager cm,int rownum)
{
return false;
}
public new bool readonly
{
get {return true;}
}
}
下面的代碼說明了如何使用類datagridjoincolumn。新建一個(gè)windows程序,加入一個(gè)datagrid和一個(gè)sqlconnection,連接數(shù)據(jù)庫northwind。 在form_load中加入下面代碼:
private void form1_load(object sender, system.eventargs e)
{
sqldataadapter sda1=new sqldataadapter("select employeeid,lastname,firstname from employees",this.sqlconn);
sqldataadapter sda3=new sqldataadapter("select orderid,employeeid,orderdate,requireddate from orders",this.sqlconn);
ds=new dataset();
sda1.fill(ds,"emp");
sda3.fill(ds,"ord");
ds.relations.add("ord_emp",ds.tables["emp"].columns["employeeid"],ds.tables["ord"].columns["employeeid"]);
ds.tables["ord"].columns.add("lastname",typeof(string));
ds.tables["ord"].columns.add("firstname",typeof(string));
datagridtablestyle dt=new datagridtablestyle();
datagridcolumnstyle dc;
dc=new datagridtextboxcolumn();
dc.mappingname="orderid";
dc.headertext="orderid";
dt.gridcolumnstyles.add(dc);
dc=new datagridtextboxcolumn();
dc.mappingname="employeeid";
dc.headertext="employeeid";
dt.gridcolumnstyles.add(dc);
dc=new jointextboxcolumn("ord_emp",ds.tables["emp"].columns["firstname"]);
dc.mappingname="firstname";
dc.headertext="firstname";
dt.gridcolumnstyles.add(dc);
dc=new jointextboxcolumn("ord_emp",ds.tables["emp"].columns["lastname"]);
dc.mappingname="lastname";
dc.headertext="lastname";
dt.gridcolumnstyles.add(dc);
dc=new datagridtextboxcolumn();
dc.mappingname="orderdate";
dc.headertext="orderdate";
dt.gridcolumnstyles.add(dc);
dc=new datagridtextboxcolumn();
dc.mappingname="requireddate";
dc.headertext="requireddate";
dt.gridcolumnstyles.add(dc);
dt.mappingname="ord";
this.datagrid1.tablestyles.add(dt);
this.datagrid1.datasource=ds;
this.datagrid1.datamember="ord";
}