DataGrid Web Control 连载之八

简介:
   这个系列是在开发过程中对遇到的技术问题的一个总结,当时对这个控件的了解不是很多,但是根据需要实现的功能,不得不查阅N多资料,在MSDN文档中只有英文的说明,我整理并翻译了出来,在此和大家一起分享。转载请加此连接[url]http://august.blog.51cto.com[/url],谢谢!
     在类似于Microsoft Hotmail的应用程序中,用户可以通过勾选CheckBox选中多项,然后对所有选中的项进行操作,如删除或复制它们。
为了添加这样的功能,要在DataGrid中添加一个模板列,并在该模板列中加一个CheckBox。当页面运行的时候,用户就可以对他们需要的项进行选择。
    实际执行用户的动作时,可以遍历DataGrid的Items集合检查适当的列(单元格)来看CheckBox是否被选中,下面的例子显示了如何根据用户的选择来删除DataSet中的行。假设数据集.dsBook中包含了一个Books表。
private void btnDelete_Click(object sender, System.EventArgs e)
{
   int i = 0;
   CheckBox cb;
   int bookid;
   dsBooks.BooksRow dr;
   foreach(DataGridItem dgi in this.DataGrid1.Items)
   {
      cb = (CheckBox) dgi.Cells[0].Controls[1];
      if(cb.Checked)
      {
         // Determine the key of the selected record ... 
         bookid = (int) DataGrid1.DataKeys;
         // ... get a pointer to the corresponding dataset record ...
         dr = this.dsBooks1.Books.FindBybookid(bookid);
         // ... and delete it.
         dr.Delete();
      }
      i++;
   }
   this.sqlDataAdapter1.Update(this.dsBooks1);
   this.sqlDataAdapter1.Fill(this.dsBooks1);
   DataGrid1.DataBind();
}
需要注意的几点:
     你可以通过下面的标准方法来检查CheckBox是否被选中:为从模板列中得到控件值,首先要从单元格的控件集合中得到一个对象,并且进行适当的类型转换。如果你得到了一个CheckBox控件,要记住它通常是第二个(索引为1)控件,因为在它前面有一个文字控件(即使它为空)。
     如果你要删除一个记录,必须通过DataSet中的关键字来实现,而不是通过offset。DataGrid控件中项的索引可能并不与表中同样记录的索引匹配,即使开始时匹配在删除第一条记录后就不再匹配了,这里代码通过DataGrid的DataKey集合得到记录的关键字,然后通过在DataSet表中使用FindByKey()方法来实现要删除的记录。
在DataSet中的记录被删除后(技术上,它们只是被做了删除标记),你要调用DataAdapter的Updata方法来从数据库中实际删除他们,然后代码从数据库刷新DataSet并重绑定回DataGrid.
   一次编辑多行
   DataGrid控件中编辑行的标准方法是通过添加一个“编辑、更新、取消”按钮到DataGrid的列中,只允许用户一次编辑一行,如果用户要编辑多行,他们必须单击“编辑”按钮,然后修改,再点击“更新”按钮,每一行都要这么做。
在某些情况下,一个有效的变通方法就是配置DataGrid使它默认就是编辑模式,这种情形DataGrid总是通过TextBox或者其它控件来显示可编辑的数据。用户不需要再将其转为编辑模式,典型情况下,用户作出任何想要的更改,然后单击一个按钮(并不是DataGrid中的按钮)来一次提交所有的更改。
    你可以在任何数据模型下使用这种编辑方式,无论是通过DataSet或者直接通过数据命令使用数据源。为将DataGrid设定为多行可编辑模式,添加列并将所有可编辑列转化为模板列,在DataGrid生成器中的列标签中,选中一列,选择窗口底部的“将此列转化为模板列”,可以通过右键→编辑模板来对模板进行编辑。
    添加编辑控件项模板,注意你不是像通常那样将它们添加到编辑项模板,因为在编辑模式下,行不会被显示,也就是说,在ItemTemplate中才包含可编辑控件。
像一般情况下那样设定数据绑定,你需要单独为每个可编辑控件进行绑定,一个典型的数据绑定表达式可能是这样:DataBinder.Eval(Container,”DataItem.title”)
加载DataGrid与一般情况无异,但是更新时稍有不同,当用户点击更新按钮时,你需要遍历整个DataGrid,一项一项地从可编辑控件中提取值,并将其指定给命令的参数,然后为每一项执行更新操作‘
private void btnUpdate_Click(object sender, System.EventArgs e)
{
   int i;
   DataGridItem dgi;
   int bookid;
   TextBox TextBoxTitle;
   CheckBox CheckBoxInStock;
   TextBox TextBoxPrice;
 
   for(i = 0; i <= DataGrid1.Items.Count -1 ; i++)
   {
      dgi = DataGrid1.Items;
      Label LabelBookId = (Label) dgi.Cells[0].Controls[1];
      bookid = int.Parse(LabelBookId.Text);
      TextBoxTitle = (TextBox) dgi.FindControl("TextBoxTitle");
      CheckBoxInStock = (CheckBox) dgi.FindControl("CheckBoxInStock");
      TextBoxPrice = (TextBox) dgi.FindControl("TextBoxPrice");
      this.dcmdUpdateBooks.Parameters["@bookid"].Value = bookid;
      this.dcmdUpdateBooks.Parameters["@Title"].Value = TextBoxTitle.Text;
      this.dcmdUpdateBooks.Parameters["@instock"].Value = 
CheckBoxInStock.Checked;
      this.dcmdUpdateBooks.Parameters["@Price"].Value = 
float.Parse(TextBoxPrice.Text);
      this.sqlConnection1.Open();
      this.dcmdUpdateBooks.ExecuteNonQuery();
      this.sqlConnection1.Close();
   }
}
检查出变化的项
    上面展示的更新策略的一个不足之处在于:如果只有很少的行发生变更,那么为每一行(无论变化与否)都向DataSet或者数据库发出更新命令,效率是比较低的,如果你使用的是一个DataSet,那么可以添加逻辑来检查DataGrid的控件与DataSet行中的对应列之间是否有变化,如果像上例那样,没有使用DataSet,就不能很容易地做出比较,因为那将涉及一次数据库的访问与回传。
    对于以上两种数据源都适应的一个策略是,确定一个能在你做出更新之前就能检查出该行是否为“脏数据”的方法,实现它的一个确定的方法是处理行中控件的Changed事件,相似地,对于CheckBox控件,可以使用其CheckedChanged事件。
在这些事件的处理中你可以保持一个将要更新的行的列表。通常,最好的方法是保持手影响的行的主键。比如:可以声明一个ArrayList对象来存储将要更新的行的主键。
假如要为上面的例子采用这样的策略,创建一个ArrayList对象的实例作为Page类的一个成员。
Protected  ArrayList bookidlist = new ArrayList();
然后创建一个事件处理程序,在控件发生变化时,向ArrayList对象中添加书的ID。下面的代码是一个当TextBox产生TextChanged事件成一个CheckBox产生CheckedChanged事件时触发的一个。事件处理程序:
protected void RowChanged( object sender, System.EventArgs e)
{
   DataGridItem dgi = (DataGridItem)(((Control)sender).NamingContainer);
   Label bookidlabel = (Label) dgi.Cells[0].Controls[1];
   int bookid = int.Parse(bookidlabel.Text);
   if (!bookidlist.Contains(bookid))
   {
      bookidlist.Add(bookid);
   }
}
注意:方法不能声明为private,否则后面就不能对其绑定。
     默认情况下,change事件并不将page回传到服务器,理解这点是十分有益的,经常是页面通过其它某种方式提交的时候才触发该事件(通过单击事件)。在页面处理过程中,页面和其上的所有控件被初始化,然后所有的change事件被触发。只有当change事件处理程序完成,控件的click事件发生,才引起页面的回传。
     在上面的RowChanged方法中,代码需要从当前项获得书的ID,但它并不把该项传给你(就象许多DataGrid事件一样),因此你要解决这个问题,由事件的Sender参数获得它的NamingContainer属性,也就是DataGrid项,由DataGrid项向下通过Cell.controls就可以得到用于显示书的ID的Label控件的值。
    在加入前需要检查书的ID尚未存在于数组中,行中的每个控件都单独产生一个事件,所以如果行中多于一个控件发生了change事件,就可以防止多项向数组中添加该书的ID号。控件的change事件总是在click事件之前被触发和处理。因此,你可以在change事件中创建ArrayList,并要确保它在用于提交表单的按钮的click事件处理程序(本例中是btnUpdate_click)执行时是可用的。
     既然你已经有了ArrayList,现在可以对管理更新的事件处理程序进行一个小的修改,在btnUpdate_click事件中,对DataGrid项循环时,添加一个判断,来检查当前的书的ID号是否是已经在ArrayList中,如果在,则执行更新:
private void btnUpdate_Click(object sender, System.EventArgs e)
{
   int i;
   DataGridItem dgi;
   int bookid;
   //Rest of declarations here
 
   for(i = 0; i <= DataGrid1.Items.Count -1 ; i++)
   {
      dgi = DataGrid1.Items;
      TableCell tc = dgi.Cells[0];
      string s = dgi.Cells[0].Text;
      Label LabelBookId = (Label) dgi.Cells[0].Controls[1];
      bookid = int.Parse(LabelBookId.Text);
      if (bookidlist.Contains(bookid)) 
      {
         // Update code here
      }
   }
}
还有一个任务:绑定处理程序列控件的事件,在VS中,只有通过HTML视图来完成,控件在后台代码(code-behind)文件中并没有默认地实例化,因此,代码工具并不支持它们,将.aspx文件切换到HTML视图,在每个控件的声明元素中添加下面的语法:
<asp:TemplateColumn HeaderText="title">
   <ItemTemplate>
      <asp:TextBox OnTextChanged="RowChanged"
         id=TextBoxTitle runat="server"
         Text='<%# DataBinder.Eval(Container, "DataItem.title") %>'>
      </asp:TextBox>
   </ItemTemplate>
</asp:TemplateColumn>
 
<asp:TemplateColumn HeaderText="instock">
   <ItemTemplate>
      <asp:CheckBox id=cbInStock OnCheckedChanged="RowChanged"
        runat="server" 
        Checked='<%# DataBinder.Eval(Container, "DataItem.instock") %>'>
      </asp:CheckBox>
   </ItemTemplate>
</asp:TemplateColumn>
      TextBox和CheckBox均可以在各自的change事件触发时调用相同的方法,因为两个事件句柄具有同样的签名(signature),对于一个ListBox的控件或TextBox和CheckBox均可以在各自的change事件触发时调用相同的方法,因为两个事件句柄具有同样的签名。对于一个ListBox控件或Drop-Down List控件也是如此,它们的SelectedIndexChanged事件也传递相同的参数。


本文转自 august 51CTO博客,原文链接:http://blog.51cto.com/august/6920,如需转载请自行联系原作者
相关文章
|
7月前
|
SQL 存储 Oracle
C# Web控件与数据感应之 Control 类
C# Web控件与数据感应之 Control 类
|
Web App开发 安全 前端开发
|
Web App开发
RDIFramework.NET框架Web中datagrid与treegrid控件自动生成右键菜单与列标题右键菜单
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/chinahuyong/article/details/51490149   在实际应用中常可以看到数据展示控件有右键菜单的功能,对应的列标题也可以右键弹出快捷菜单设置指定列的显示与隐藏等功能。
918 0