高分请指教:如何用dataGrid实现编辑datatable中的单行记录(行式编辑窗口)?
即表的某列变行样式,一行记录变为一列。
在winform下,
由于表的列不固定,所以不易实现在Form中固定label(显示提示)、textbox(或comboBox等)录入某行的记录内容。所以想采用dataGrid来实现,第一列表示提示,第二列表示录入的内容。
现在的问题是,第二列的录入样式不确定,可能是textBox,可能是combobox,可能是日期控件,可能是checkbox,如果自定义DataGridTextBoxColumn,加入combobox,日期控件,checkbox等,在录入时某行的改变会影响到相同类型的行的内容。
金蝶软件实现了类似的功能。有遇到过这种情况的请多多指教。由代码最好。
或者请提出设计思路。
问题点数:100、回复次数:13Top
1 楼yblcgw(黑马之王)回复于 2004-09-03 18:57:19 得分 40
思路:获取当前鼠标的x,y,然后根据x,y获取当前的行和列(以上完全可以实现,没有问题)然后用switch来显示不同的控建,我的就是这么做的,不知道哪位高手还有其它的想法Top
2 楼clearma(明天早起床)回复于 2004-09-03 19:17:44 得分 0
我有一个表1,存放要编辑的另外一个表2的结构,所以行列的获取好办。
如表1
id,name,colType colName
1 姓名 text name
2 性别 combobox sex
3 出生年月 DataTimePicker birthday
4 婚否 checkbox isSex
表2
id,name,sex,birthday,isSex
1 张三 0 2004-01-01 0
2 里斯 1 2004-01-01 0
在表1中赠加一列(value)作为存放输入内容的值,然后dataGrid绑定到表1,
dataGrid两列,第一列mappingname: name(表1)
第二列 mappingname :value(表1)
根据操作时时新增还是修改,决定是否提前把表2中的某行的数据加载到表1的value中
这样dataGrid实际就是4行,如下:
name value
姓名 _________(textbox)
性别 ________(combobox)
出生年月 ________(DataTimePicker)
婚否 ________(checkBox)
出生地 ________(combobox)
问题在于比如设置dagaGrid第二行combobox类型时,他的数据源与其他行(还有很多行)的combobox的数据源不易区分。
当重写DataGridTextBoxColumn的getrowValue时,容易出现第二行与其他行的数据一致的情况。
当重写Edit时,倒没有问题,也就是说当鼠标点击某个cell时,出来的控件都是对的,因为这时可以获取rowNum,我可以使用DataRow来找到表1种的这一行,根据colType然后决定显示哪一个控件。
这种方法是否可行。
Top
3 楼zhpsam109(JACKY.昊昊)回复于 2004-09-03 19:34:35 得分 20
录入时某行的改变会影响到相同类型的行的内容???怎么会影响呢?Top
4 楼clearma(明天早起床)回复于 2004-09-03 19:48:58 得分 0
回复人: zhpsam109(孤寂无边) ( ) 信誉:100 2004-09-03 19:34:00 得分: 0
录入时某行的改变会影响到相同类型的行的内容???怎么会影响呢?
-----------------------
因为DataGridTextBoxColumn中只有1个TextBox,难道编辑完一个cell后,必须要重新GetColumnValueAtRow码?有可能啊。否则的话,当点击下一个cell时,值会跟前一个cell的值相同。
我在看看。
Top
5 楼clearma(明天早起床)回复于 2004-09-03 21:35:38 得分 0
如上,如果点击第二行的第二列的cell则首先会触发edit事件,好像接着还会触发getColumnValueAtRow,重新遍历每一行,我在GetColumnValueAtRow中设置了当前combobox的dataSource,所以最后第二行的第二列的cell的datasource是最后一个combobox类型的cell的数据源,而非当前cell所对应的数据源。
这个问题怎么办?Top
6 楼clearma(明天早起床)回复于 2004-09-04 09:33:55 得分 0
还是没解决阿。
请明白datagridtextboxcolumn 类的高手指点一下事件的触发过程。Top
7 楼lovemeet(天意)回复于 2004-09-04 12:01:53 得分 20
yblcgw(黑马之王)提到的我看差不多。
private void dataGrid_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
int i= this.dataGrid .HitTest((new Point(e.X, e.Y))).Row ;
int j=this.dataGrid .HitTest ((new Point (e.X ,e.Y ))).Column ;
if(!(j==-1|| i==-1 ))
{ this.btnDelete .Enabled =true; dgCellContext=Convert.ToInt16 (this.dataGrid [i,0]);
UserNameDelete=Convert.ToString (this.dataGrid [i,1]); }
else
{
this.btnDelete .Enabled =false;
}
}
获得DataGrid的行号和列号不难Top
8 楼clearma(明天早起床)回复于 2004-09-06 17:51:07 得分 0
我的意思是把dataGridColumnStyle定义为包含多个控件的组件,控件的显示与否与实际数据源的每行(或者说dataGrid的每行)有关。
但是由于我不明白样式对象dataGridColumnStyle的事件触发过程,比如在用鼠标点击一个单元格后会触发那些事件,造成了在实际dataGrid邦定样式,邦定数据源后,这一列中相同类型的cell,会出现相同值的情况。(估计每点击cell后重新执行了GetColumnValueAtRow)。我的程序中也是用如下方式实现的:
protected override object GetColumnValueAtRow(System.Windows.Forms.CurrencyManager source, int rowNum)
{
object ReturnValue=null;
DataRow Dr=DataSet.Tables [1].Rows [rowNum];
string FilterString;
switch ((string)Dr["colType"])
{
case "text":
ReturnValue=base.GetColumnValueAtRow(source, rowNum);
break;
case "list":
//获取数据源的值
if (CurrentNum!=0) //CurrentRow鼠标点击行
{
if( CurrentNum!=rowNum)
{
rowNum=CurrentNum;
Dr=DataSet.Tables [1].Rows [rowNum];
}
}
/*下面是我的combobox数据源的加载过程,因为多个combobox的数据源是一个表,但是他们的类别代码不同,就好比性别,身份,学历等下拉列表内容都放在一个表中,通过某编号来区分。所以combobox中要求出现内容不一样,我想这针对多个表也是如此吧。
*/
FilterString ="deptItemId='"+(string)Dr["id"]+"'";
DataView dv=new DataView (DataSet.Tables "dept_item_code"],FilterString,"id",DataViewRowState.CurrentRows);
ColumnComboBox.DataSource =dv;
ColumnComboBox.DisplayMember ="name";
ColumnComboBox.ValueMember = "id";
//DataView dv = (DataView)this.ColumnComboBox.DataSource;
//如果这种方式引用,毫无疑问comBoBox中显示的是上一个combobox应该显示的内容。
object s = base.GetColumnValueAtRow(source, rowNum);
int rowCount = dv.Count;
int i = 0;
while (i < rowCount)
{
if( s.Equals(dv[i][this.ColumnComboBox.ValueMember]))
{
break;
}
++i;
}
FilterString="";
if(i < rowCount)
ReturnValue=dv[i][this.ColumnComboBox.DisplayMember];
break;
case "list2":
ReturnValue=base.GetColumnValueAtRow(source, rowNum);
break;
case "date":
ReturnValue=base.GetColumnValueAtRow(source, rowNum);
break;
case "checkbox":
ReturnValue=base.GetColumnValueAtRow(source, rowNum);
break;
default:
ReturnValue=base.GetColumnValueAtRow(source, rowNum);
break;
}
return ReturnValue;
}
代码写的很糟糕,不好意思,为了调试有些东西是临时加上的,还没有优化。
其实目前只判断了list型的,即combobox型的,其他的控件的返回值都是类似于textbox的。
Top
9 楼clearma(明天早起床)回复于 2004-09-09 11:35:14 得分 0
upTop
10 楼happy3613(happy3613)回复于 2004-09-09 13:43:01 得分 20
void DataGrid1_UpdateCommand(object source, System.Web.UI.WebControls.DataGridCommandEventArgs e)
{
SqlConnection myConnection = new SqlConnection(ConfigurationSettings.ConnectionStrings["SqlServices"].ConnectionString);
string id1 = DataGrid1.Items[(int)e.Item.ItemIndex].Cells[0].Text;
string sl=((TextBox)e.Item.Cells[4].Controls[0]).Text;
DataTable dt = (DataTable)Session["myTable"];
dt.Rows[e.Item.ItemIndex][3] = sl.ToString();
dt.Rows[e.Item.ItemIndex][6] = Convert.ToDouble(dt.Rows[e.Item.ItemIndex][3]) * Convert.ToDouble(dt.Rows[e.Item.ItemIndex][4]);
dt.AcceptChanges();
DataGrid1.EditItemIndex = -1;
DataGrid1.DataSource = ((DataTable)Session["myTable"]).DefaultView;
DataGrid1.DataBind();
}Top
11 楼clearma(明天早起床)回复于 2004-09-09 19:35:44 得分 0
楼上请问什么思路,webform 与winform毕竟有不同,你的代码我不太明白。Top
12 楼clearma(明天早起床)回复于 2004-09-10 13:23:24 得分 0
今天重新看了msdn中的GetColumnValueAtRow,感觉以前分析的不对阿。
protected internal virtual object GetColumnValueAtRow(
CurrencyManager source,
int rowNum
);
看他的两个参数,source是当前的绑定管理对象,rowNum则是指定数据源的Position
不知道微软的代码怎么写的,估计也就是利用了CurrencyManager的,然后强制转换为dataview等,然后利用dataview[rowNum]获取出数据源的值。
以下内容通过设置断点分析,paint的内容为猜测,请各位指教:
(1)dataGrid首先画出了框架,标题,边框等。这时肯定要用到tableStyle(不管是否自定义,特别是headerText,width等)
(2)接着从邦定数据源的第0行开始初始每个cell的值,使用GetColumnValueAtRow方法。
paint的顺序是按照列来进行的。即(0,0),(0,1),(0,n)
(3)paint的过程不太清楚,比如画表格线,用的text的边框还是画的线呢?
(3)当重复经过某一列时,比如此列的类型为ComboBoxColumn(继承自textBoxColumn),那么还是要使用GetColumnValueAtRow()方法。
(4)完成
(5)如果鼠标点击某个cell(非其他),则事件的触发不很清楚,
是mouseDown,mouseEnter,mouseUp,还是触发离开(Leave)CurrentCellChanged等
这应该涉及到多个对象的事件触发过程。
(6)接下来应该是Edit()方法,这时会不会GetColumnValueAtRow()
(7)如果修改后离开的话应该有Commit(),是否有ConcedeFocus()呢?
我的问题是,我的ComboBoxColumn 列中只有一个ComboBox对象(无可厚非吧?),但是却要
根据数据源的行(rows[x])来动态决定所对应的ComboBox的数据源(好像不合理阿,但是必须要这样,其实是同一表,但是dataview的filter语句不同)
(a)可以在鼠标点击cell时通过重写edit()方法来设定当前cell的ComboBox的数据源,
(b)但是在离开这个cell后,会触发paint(),paint肯定会使用GetColumnValueAtRow()来重绘所有行
(c)如果在GetColumnValue()中设置ComboBoxColumn 列的ComboBox数据源,(因为这一列中针对某行ComboBox的数据源不同,显示的textBox.text就不同)}
(d)当paint完成后,GetColumnValueAtRow()中设定的是最后一行的ComboBox的数据源。这样鼠标点击的那个cell的ComboBox的数据源也被改变了
情况就是这样,应该怎么办?我相信肯定有办法,但是我现在陷入谜团了。败了。
Top
13 楼clearma(明天早起床)回复于 2004-09-13 14:43:58 得分 0
再up!到底Top




