1、建立数据层 连接数据库->建立数据集*.xsd->表中建立查询方法
2、建立业务逻辑层 包装TableAdapter方法成类
3、建立母板页和站点导航( CSS待学习)
4、使用数据源展现数据 五种数据源 编辑数据源参数 使用tableadapter方法
5、使用dropDownList过滤主-从报表
使用tableadapter方法设置数据源显示数据
(1)在主表加入列使用HyperLinkField 增加一列链接 到从表
HYperLinkField的text属性设置一个显示的链接名字
字段DataNavigateUrlFields属性绑定到超链接的NavigateUrl属性的字段例:ProductID
DataNavigateUrlFormatString属性对绑定到超链接的NavigateUrl属性的值应用的格式设定例: Default2.aspx?ProductID={0}
跨页从表 Where使用参数源QueryString接收从主表传过来的字段
(2)扩展知识点:ImageField(使用URL向GridView添加图片)
添加一个ImageField,将DataImageUrlField="PictureURL" //,图像URL绑定到PictureURL字段,
在后置代码中加入:
protected void Page_Load(object sender, EventArgs e)
{
DataTable dt = new DataTable();
// define the table’s schema
dt.Columns.Add(new DataColumn("PictureURL", typeof(string)));
// Create the four records
DataRow dr = dt.NewRow();
dr["PictureURL"] = ResolveUrl("~/Images/bbs.sakuramoon.cn__13386124_34835.jpg");
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["PictureURL"] = ResolveUrl("~/Images/bbs.sakuramoon.cn__17892967_20501.jpg");
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["PictureURL"] = ResolveUrl("~/Images/bbs.sakuramoon.cn__29111898_48281.jpg");
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["PictureURL"] = ResolveUrl("~/Images/bbs.sakuramoon.cn__29111910_25475.jpg");
dt.Rows.Add(dr);
GridView1.DataSource = dt;
GridView1.DataBind();
}
6、FormView和DetailsView中实现数据绑定的步骤
DataBinding事件触发
数据绑定到数据绑定控件
DataBound事件触发
而GridView,请使用下面的步骤
(1)DataBinding事件触发
(2)数据绑定到数据绑定控件
对于每一行数据..
a. 创建GridViewRow
//b. 触发 RowCreated 事件
c. 绑定数据到GridViewRow
d. 触发RowDataBound事件
e. 添加GridViewRow到Rows 集合
(3)DataBound事件触发
例:
(一)Northwind.ProductsRow product = (Northwind.ProductsRow)((System.Data.DataRowView)ExpensiveProductsPriceInBoldItalic.DataItem).Row;
ExpensiveProductsPriceInBoldItalic.Rows[4].Cells[1].CssClass = "ExpensivePriceEmphasis";
(二)Northwind.ProductsRow product = (Northwind.ProductsRow)((System.Data.DataRowView)FormView1.DataItem).Row;
Label unitsInStock = (Label)FormView1.FindControl("UnitsInStockLabel");
unitsInStock.CssClass = "LowUnitsInStockEmphasis";
(三)Northwind.ProductsRow products = (Northwind.ProductsRow)((System.Data.DataRowView)e.Row.DataItem).Row;
e.Row.CssClass = "AffordablePriceEmphasis";
7、TemplateField(字段模板?不知道是不是这么叫)
(一)GridView
(1)将两个数据合并到一个列中
(2)用一个Web控件来展示数据,而不是用一个简单的文本
(3)创建新模板列
例:protected string DisplayDaysOnJob(Northwind.EmployeesRow employee)
{
// 确保HiredDate不为空……如果为空的话,返回“Unknown”
if (employee.IsHireDateNull())
return "Unknown";
else
{
// 返回当前日期/时间与HireDate之间所隔的天数
TimeSpan ts = DateTime.Now.Subtract(employee.HireDate);
return ts.Days.ToString("#,##0");
}
}//写入后置代码类
<%# DisplayDaysOnJob((Northwind.EmployeesRow) ((System.Data.DataRowView) Container.DataItem).Row) %>//写入新模板列ItemTemplate
Container根本不是任何一个静态的对象或方法,它是ASP.NET页面编译器在数据绑定事件处理程序内部声明的局部变量,其类型是可以进行数据绑定的控件的数据容器类型(如在Repeater内部的数据绑定容器叫RepeaterItem),在这些容器类中基本都有DataItem属性,因此你可以写Container.DataItem,这个属性返回的是你正在被绑定的数据源中的那个数据项。
<%# DisplayDaysOnJob(Eval("HireDate")) %>//也可以用 但是后置代码类需要一个object来接收返回的object
(二)DetailsView
protected string DisplayDiscontinuedAsYESorNO(bool discontinued)
{
if (discontinued)
return "YES";
else
return "NO";
}//后台
<%# DisplayDiscontinuedAsYESorNO((bool) Eval("Discontinued")) %>//前台
(三)FormView(1小段表格填充数据例子)
<h3><%# Eval("ProductName") %>
<table border="0">
<tr>
<td >Category:</td>
<td ><%# Eval("CategoryName") %></asp:Label>
</td>
<td >Supplier:</td>
<td ><%# Eval("SupplierName")%></td>
</tr> ///Eval只读绑定 详细见Eval和Bind详解
8、GridView显示页脚
(1)配置GridView以显示它的页脚行
ShowHeader和ShowFooter属性
(2)确定统计数据。即我们应该如何计算平均价格还有库存总量
decimal _totalUnitPrice = 0m;
int _totalNonNullUnitPriceCount = 0;
int _totalUnitsInStock = 0;
int _totalUnitsOnOrder = 0;
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
Northwind.ProductsRow product = (Northwind.ProductsRow)((System.Data.DataRowView)e.Row.DataItem).Row;
if (!product.IsUnitPriceNull())
{
_totalUnitPrice += product.UnitPrice;
_totalNonNullUnitPriceCount += 1;
}
if(!product.IsUnitsInStockNull())
{
_totalUnitsInStock += product.UnitsInStock;
}
if(!product.IsUnitsOnOrderNull())
{
_totalUnitsOnOrder+=product.UnitsOnOrder;
}
}
(3)将统计信息插入到页脚行的相应的单元格中
else if(e.Row.RowType == DataControlRowType.Footer)
{
decimal avgUnitPrice = _totalUnitPrice / (decimal) _totalNonNullUnitPriceCount;
// 在相应的单元格中显示统计数据
e.Row.Cells[1].Text = "Avg.: " + avgUnitPrice.ToString("c");
e.Row.Cells[2].Text = "Total: " + _totalUnitsInStock.ToString();
e.Row.Cells[3].Text = "Total: " + _totalUnitsOnOrder.ToString();
}
9、数据插入 删除 修改
GridView有修改和删除
DetailsView有插入 删除 修改
FormView有插入 删除 修改 更自由的控制数据
其中insertVisible 设置GridView和DetailsView中字段是否在编辑或插入时被显示
10、插入 修改所关联事件
修改所关联update,GridView有RowUpdating事件 在更新按钮的update前执行,
例: protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
if (e.NewValues["UnitPrice"] != null)//newValues是获取一个字典,该字典中包含待更新行中的非键字段/值对的修改后的值.
{
MustProvideUnitPrice.Visible = false;
e.NewValues["UnitPrice"] = decimal.Parse(e.NewValues["UnitPrice"].ToString(), System.Globalization.NumberStyles.Currency);//转换值为decimal型
}
else
{
MustProvideUnitPrice.Visible = true;
MustProvideUnitPrice.CssClass = "Warning";
e.Cancel = true;//返回更新界面
}
}
另注:GridView字段ApplyFormatInEditMode属性为true(默认为false),可以把DataFormatString属性里指定的格式化指令应用到编辑界面
DetailsView插入
调用ObjectDataSource中insertting事件
protected void ObjectDataSource1_Inserting(object sender, ObjectDataSourceMethodEventArgs e)
{
e.InputParameters["CategoryID"] = 1;//填充categoryID为1
e.InputParameters["SupplierID"] = 1;
}
注::::ObjectDataSource的属性被设置为original_{0}。这个属性是使用数据源配置向导时Visual Studio自动设置的。因此,由于我们的BLL方法不需要传入原始的ProductID值,从ObjectDataSource的声明语法中删除所有这些属性设
置If you如果你只是简单地在设计视图里从属性窗口清除OldValuesParameterFormatString属性的值,这个属性会依旧存在于声明语法里,但会被设置为一个空字符串。要么从声明语法里把该属性通通删掉,要么从属性窗口,设置它的值为默认值:{0}
11、处理DAL层异常
使用RowUpdated来处理异常,
Exception –获取更新操作过程中引发的异常;如果没有抛出异常,该属性的值为null
ExceptionHandled –获取或设置一个值,它指示在更新操作过程中所引发的异常是否已在RowUpdated事件处理程序中得到处理;如果设为false(默认值),该异常将被重新引发,漏出到ASP.NET运行时
KeepInEditMode – 如果设置为true,GridView当前编辑行将维持在编辑模式;如果设置为false(默认值),当前行将恢复到只读模式
例:(1)、DAL层
protected void GridView1_RowUpdated(object sender, GridViewUpdatedEventArgs e)
{
if (e.Exception != null)
{
// Display a user-friendly message
ExceptionDetails.Visible = true;
ExceptionDetails.Text = "There was a problem updating the product. ";
if (e.Exception.InnerException != null)
{
Exception inner = e.Exception.InnerException;
if (inner is System.Data.Common.DbException)
ExceptionDetails.Text += "Our database is currently experiencing problems. Please try again later.";
else if (inner is NoNullAllowedException)
ExceptionDetails.Text += "There are one or more required fields that are missing.";
else if (inner is ArgumentException)
{
string paramName = ((ArgumentException)inner).ParamName;
ExceptionDetails.Text += string.Concat("The ", paramName, " value is illegal.");
}
else if (inner is ApplicationException) ExceptionDetails.Text += inner.Message;
}
e.ExceptionHandled = true;
e.KeepInEditMode=true;
}
}
(2)、BLL层
if (unitPrice != null && !product.IsUnitPriceNull())
if (unitPrice > product.UnitPrice * 2)
throw new ApplicationException("When updating a product price," + " the new price cannot exceed twice the original price.");
12、验证控件
为确保用户录入数据都是有效的,ASP.NET提供了5种内建的验证控件来验证单一控件的值:
(1) RequiredFieldValidator – 计算输入控件的值以确保用户输入值
(2) CompareValidator – 将输入控件的值同常数值或其他输入控件的值相比较,以确定这两个值是否与由比较运算符(小于、等于、大于、类型等等)指定的关系相匹配
(3) RangeValidator – 计算输入控件的值,以确定该值是否在指定的上限与下限之间
(4)RegularExpressionValidator – 计算输入控件的值,以确定该值是否与某个正则表达式 所定义的模式相匹配
(5)CustomValidator – 计算输入控件的值以确定它是否通过自定义的验证逻辑
例:1、RequiredFieldValidator 设置 ControlToValidate 指向需要验证的textBox(或其它),ErrorMessage属性设置错误信息,
2、CompareValidator 设置ControlToValidate 指向需要验证的textBox(或其它),ErrorMessage属性设置错误信息,operator属性设置对值的比较操作,ValueToCompare属性设置用于进行比较的值,Type设置值类型,ValidationGroup设置验证程序所属的组(或所属的web控件),
注:ValidationSummary control为总结控件 可以显示那些检测到无效数据的验证控件的ErrorMessage,以文本方式在页上某个位置概述错误结果,或者通过一个客户端消息框,此控件位置无关紧要,ShowMessageBox属性设置是否以对话框形式报错,
13、定制数据修改界面
GridView填加DropDownList和RadioButtonList
重载updateProduct()
[System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Update, false)]
public bool UpdateProduct(string productName, int? categoryID, int? supplierID, bool discontinued, int productID)
{
Northwind.ProductsDataTable products = Adapter.GetProductByProductID(productID);
if (products.Count == 0)
// 如果没有匹配记录,返回false
return false;
Northwind.ProductsRow product = products[0];
product.ProductName = productName;
if (supplierID == null) product.SetSupplierIDNull(); else product.SupplierID = supplierID.Value;
if (categoryID == null) product.SetCategoryIDNull(); else product.CategoryID = categoryID.Value;
product.Discontinued = discontinued;
// 更新产品记录
int rowsAffected = Adapter.Update(product);
// 成功更新后返回true,否则返回false
return rowsAffected == 1;
}
将GridView字段转换为模板 用DropDownList和RadioButtonList替换原有的label或checkBox等等
注:数据源配置中 第二项值为显示的值 第三项为后台处理值(竟然现在才知道)
(1)设置DropDownList之后,第一项实际为NULL,需要手动改变 编辑控件的DataBindings中SelectValue设置相应绑定字段,
在Product表中的CategoryID 和 SupplierID列允许为NULL
需要在DropDownList中加入NULL项,先将DropDownList的AppendDataBoundItems属性设置为true。接着,用<asp:ListItem>元素来增加一个NULL列表项,元素标记大致如下:
<asp:DropDownList ID="Categories" runat="server" DataSourceID="CategoriesDataSource" DataTextField="CategoryName" DataValueField="CategoryID" SelectedValue='<%# Bind("CategoryID") %>' AppendDataBoundItems="True"> <asp:ListItem Value="">(None)</asp:ListItem>//*******此处一定注意,通过显式设置Value="",否则在修改更新时会出现无法写入数据库,
</asp:DropDownList>
(2)用RadioButtonList表示Discontinued状态
将Discontinued的checkBox替换为RadioButtonList,设置RadioButtonLists的两个单选按钮项,一个为“Active”标签,值为“False”,另一个为“Discontinued”标签,值为“True”。(控件Items属性设置),由于只有修改状态时才可以改变Discontinued,所以把ItemTemplate(普通模板)时RadioButtonList的Enabled属性为false,编辑控件的DataBindings中SelectValue设置相应绑定字段
14、实现开放式并发
当两个用户同时访问一个页面,一个用户可能更新的事另一个用户已经删除的记录。或者,在一个用户加载页面跟他点击删除按钮之间的时间里,另一个用户修改了这条记录的内容。有下面三中并发控制策略可供选择:
当两个用户同时访问一个页面,一个用户可能更新的事另一个用户已经删除的记录。或者,在一个用户加载页面跟他点击删除按钮之间的时间里,另一个用户修改了这条记录的内容。
有下面三中并发控制策略可供选择:
什么都不做 –如果并发用户修改的是同一条记录,让最后提交的结果生效(默认的行为)
开放式并发(Optimistic Concurrency) - 假定并发冲突只是偶尔发生,绝大多数的时候并不会出现; 那么,当发生一个冲突时,仅仅简单的告知用户,他所作的更改不能保存,因为别的用户已经修改了同一条记录
保守式并发(Pessimistic Concurrency) – 假定并发冲突经常发生,并且用户不能容忍被告知自己的修改不能保存是由于别人的并发行为;那么,当一个用户开始编辑一条记录,锁定该记录,从而防止其他用户编辑或删除该记录,直到他完成并提交自己的更改
为了更新或删除能够成功,原始值必须与数据库中相应的值一致,例姓名:大头 年龄23;两人同时打开网页进入到修改模式,甲修姓名为小头并更新,乙此时看到的仍然是姓名:大头,这时乙修改年龄为25时并更新时会出现无法更新,因为甲已经将姓名修改为小头,而乙姓名的原始值为大头,与数据库中的值不一致,所以无法修改.
(一)创建一个支持开放式并发的数据访问层
在DAL文件夹中建立一个新文件,在TableAdapter配置页面中高级选项中勾选上“使用开放式并发"
(二)创建一个支持启用了开放式并发的DAL的业务逻辑层
在BLL文件夹中建立一个新文件,填加如下代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using NorthwindOptimisticConcurrencyTableAdapters;
/// <summary>
///ProductsOptimisticConcurrencyBLL 的摘要说明
/// </summary>
[System.ComponentModel.DataObject]
public class ProductsOptimisticConcurrencyBLL
{
private ProductsOptimisticConcurrencyTableAdapter _productsAdapter = null;
protected ProductsOptimisticConcurrencyTableAdapter Adapter
{
get
{
if (_productsAdapter == null)
_productsAdapter = new ProductsOptimisticConcurrencyTableAdapter();
return _productsAdapter;
}
}
[System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, true)]
public NorthwindOptimisticConcurrency.ProductsOptimisticConcurrencyDataTable GetProducts()
{
return Adapter.GetProducts();
}
[System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Delete, true)]
public bool DeleteProduct(int original_productID, string original_productName, int? original_supplierID, int? original_categoryID,string original_quantityPerUnit, decimal? original_unitPrice, short? original_unitsInStock,short? original_unitsOnOrder, short? original_reorderLevel, bool original_discontinued)
{ int rowsAffected = Adapter.Delete(original_productID,original_productName,original_supplierID,
original_categoryID,original_quantityPerUnit,original_unitPrice,original_unitsInStock,original_unitsOnOrder,original_reorderLevel,original_discontinued);
return rowsAffected == 1;
}
protected void AssignAllProductValues(NorthwindOptimisticConcurrency.ProductsOptimisticConcurrencyRow product,string productName, int? supplierID, int? categoryID, string quantityPerUnit,decimal? unitPrice, short? unitsInStock, short? unitsOnOrder, short? reorderLevel,bool discontinued)
{ product.ProductName = productName;
if (supplierID == null) product.SetSupplierIDNull(); else product.SupplierID = supplierID.Value;
if (categoryID == null) product.SetCategoryIDNull(); else product.CategoryID = categoryID.Value;
if (quantityPerUnit == null) product.SetQuantityPerUnitNull(); else product.QuantityPerUnit = quantityPerUnit;
if (unitPrice == null) product.SetUnitPriceNull(); else product.UnitPrice = unitPrice.Value;
if (unitsInStock == null) product.SetUnitsInStockNull(); else product.UnitsInStock = unitsInStock.Value;
if (unitsOnOrder == null) product.SetUnitsOnOrderNull(); else product.UnitsOnOrder = unitsOnOrder.Value;
if (reorderLevel == null) product.SetReorderLevelNull(); else product.ReorderLevel = reorderLevel.Value;
product.Discontinued = discontinued;
}
[System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Update, true)]
public bool UpdateProduct(string productName, int? supplierID, int? categoryID, string quantityPerUnit,decimal? unitPrice, short? unitsInStock, short? unitsOnOrder, short? reorderLevel,bool discontinued, int productID,string original_productName, int? original_supplierID, int? original_categoryID,string original_quantityPerUnit, decimal? original_unitPrice, short? original_unitsInStock,short? original_unitsOnOrder, short? original_reorderLevel, bool original_discontinued,int original_productID)
{NorthwindOptimisticConcurrency.ProductsOptimisticConcurrencyDataTable products = Adapter.GetProductByProductID(original_productID);
if (products.Count == 0)
return false;
NorthwindOptimisticConcurrency.ProductsOptimisticConcurrencyRow product = products[0];
AssignAllProductValues(product, original_productName, original_supplierID,
original_categoryID, original_quantityPerUnit, original_unitPrice,
original_unitsInStock, original_unitsOnOrder, original_reorderLevel,
original_discontinued);
product.AcceptChanges();
AssignAllProductValues(product, productName, supplierID, categoryID, quantityPerUnit, unitPrice,
unitsInStock, unitsOnOrder, reorderLevel, discontinued);