【发布时间】:2014-10-28 13:41:20
【问题描述】:
单击“保存”将数据保存到数据库后,我的 GridView RowDataBound 事件出现问题。
我有一个包含 5 列的网格:标签名称、当前时间戳、当前值、新日期、新值。
这个想法是用户将输入新日期/新值以更新数据库中的数据。当前时间戳和当前值是已存储在数据库中的内容。
我使用 JQuery 编辑器输入日期。
当我点击保存时,我有服务器端验证来检查输入的值。如果数据有效,则会在“新值”列中的文本下方显示一条消息以表明这一点。如果验证失败,则会在“新值”列中显示一条消息。
New Date 和 New Value 列是 TemplateField 的。 New Value TemplateField 包含一个带有两个标签的面板 - 一个用于 OK 状态,另一个用于错误。
当我调用任何 e.Row.FindControl(...) 时,MyDataGrid_RowDataBound 中发生错误,该错误是在我重新绑定时单击 Save 按钮触发的。
如果输入了有效值,它可以正常工作,但如果输入了无效值,则会出错。为了简化场景,输入 100 表示有效值,输入其他任何值表示无效。
这个 WebForm 一直是我一生的麻烦。也许我不应该使用 GridView。
无论如何,如果您能帮助我找出问题所在,我将不胜感激。也许是表单代码的更好方法。
我已从我的解决方案中获取代码并将其移动到独立解决方案中以重现该问题。我已经删除了数据库访问并填充了数据结构。这仅在页面初始加载时在页面加载中完成(一次)。
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<link rel="stylesheet" href="Styles/jquery-ui-timepicker-addon.css" />
<link rel="stylesheet" href="Styles/jquery-ui-1.10.1.custom.css" />
<link rel="stylesheet" href="Styles/jquery-ui-1.10.1.custom.min.css" />
<script src="Scripts/jquery-1.9.1.js"></script>
<script src="Scripts/jquery-ui-1.10.1.custom.js"></script>
<script src="Scripts/jquery-ui-1.10.1.custom.min.js"></script>
<script src="Scripts/jquery-ui-timepicker-addon.js"></script>
</head>
<body>
<script type="text/javascript">
/** Disable backkey */
$(document).unbind('keydown').bind('keydown', function (event) {
var doPrevent = false;
if (event.keyCode === 8) {
var d = event.srcElement || event.target;
if ((d.tagName.toUpperCase() === 'INPUT' && (d.type.toUpperCase() === 'TEXT' || d.type.toUpperCase() === 'PASSWORD' || d.type.toUpperCase() === 'FILE'))
|| d.tagName.toUpperCase() === 'TEXTAREA') {
doPrevent = d.readOnly || d.disabled;
} else {
doPrevent = true;
}
}
if (doPrevent) {
event.preventDefault();
}
});
$(function () {
$(".datetimepicker").datetimepicker({
changeMonth: true,
changeYear: true
});
});
$(function () {
$(".datepicker").datepicker({
changeMonth: true,
changeYear: true
});
});
$(function () {
$(".timepicker").timepicker({ showTimezone: false });
});
</script>
<form id="form1" runat="server">
<div>
<asp:GridView ID="MyDataGrid" runat="server"
EnableModelValidation="True"
DataKeyNames="Id"
AutoGenerateColumns="False"
AutoGenerateSelectButton="False"
EmptyDataText="There is no plant data configured."
OnRowDataBound="MyDataGrid_RowDataBound">
<Columns>
<asp:BoundField DataField="Name" SortExpression="Name" HeaderText="Tag Name"></asp:BoundField>
<asp:BoundField DataField="Date" SortExpression="Date" HeaderText="Current Timestamp"></asp:BoundField>
<asp:BoundField DataField="Value" SortExpression="Value" HeaderText="Current Value"></asp:BoundField>
<asp:TemplateField HeaderText="New Date<BR/>MM/DD/YYYY HH:MM">
<ItemTemplate>
<asp:TextBox ID="txtNewDate" runat="server" CssClass="datetimepicker"></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="New Value">
<ItemTemplate>
<asp:TextBox ID="txtNewValue" runat="server"></asp:TextBox>
<asp:Panel ID="ErrorPanel" runat="server">
<br />
<asp:Label ID="lblError" runat="server" ForeColor="Red"></asp:Label>
<asp:Label ID="lblStatus" runat="server" ForeColor="#66cc00"></asp:Label>
</asp:Panel>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:Button ID="SaveButton" runat="server"
Text="Save Values"
ToolTip="Save the current changes."
OnClick="SaveButton_Click" />
</div>
</form>
</body>
</html>
代码背后
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI.WebControls;
public partial class _Default : System.Web.UI.Page
{
private const int COL_NEW_DATE = 3;
private const int COL_NEW_VALUE = 4;
bool canEdit = true;
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
PopulateDataGrid();
}
}
private void PopulateDataGrid()
{
// this is where i load from the database
List<RowData> data = new List<RowData>() {
new RowData() { Date = new DateTime(2000,1,1), Editable = true, Name = "Data Item 1", Value = 100.0 },
new RowData() { Date = new DateTime(2000,1,1), Editable = false, Name = "Data Item 2", Value = 120.0 },
new RowData() { Date = new DateTime(2000,1,1), Editable = true, Name = "Data Item 3", Value = 19.0 }
};
this.MyDataGrid.DataSource = data;
this.MyDataGrid.DataBind();
ViewState["GridData"] = this.MyDataGrid.DataSource;
}
private void SaveData()
{
for (int i = Page.Validators.Count - 1; i >= 0; i--)
Page.Validators.Remove(Page.Validators[i]);
ValidateData();
List<RowData> rowDataList = (List<RowData>)ViewState["GridData"];
if (this.IsValid)
{
foreach (GridViewRow row in this.MyDataGrid.Rows)
{
if (row.RowType == System.Web.UI.WebControls.DataControlRowType.DataRow && row.Enabled)
{
RowData dataItem = rowDataList[row.DataItemIndex];
var txtNewValue = row.Cells[COL_NEW_VALUE].FindControl("txtNewValue") as TextBox;
var txtNewDate = row.Cells[COL_NEW_DATE].FindControl("txtNewDate") as TextBox;
if (dataItem != null && txtNewDate != null && txtNewValue != null && !string.IsNullOrEmpty(txtNewValue.Text) && !string.IsNullOrEmpty(txtNewDate.Text))
{
var newValue = double.Parse(txtNewValue.Text);
var newDate = DateTime.Parse(txtNewDate.Text);
dataItem.InfoText = "Value written successfully for " + txtNewDate.Text;
dataItem.ErrorText = string.Empty;
dataItem.EnteredDateCache = string.Empty;
dataItem.EnteredValueCache = string.Empty;
if ((dataItem.Date.HasValue && DateTime.Compare(newDate, dataItem.Date.Value) >= 0) || !dataItem.Date.HasValue)
{
dataItem.Date = newDate;
dataItem.Value = newValue;
}
}
}
}
// save any outstanding changes if valid removed from demo
}
ViewState["GridData"] = rowDataList;
}
private void ValidateData()
{
List<RowData> rowDataList = (List<RowData>)ViewState["GridData"];
foreach (GridViewRow row in this.MyDataGrid.Rows)
{
if (row.RowType == System.Web.UI.WebControls.DataControlRowType.DataRow && row.Enabled)
ValidateDataRow(rowDataList, row);
}
}
private void ValidateDataRow(List<RowData> rowDataList, GridViewRow gridViewRow)
{
RowData rowData = rowDataList[gridViewRow.DataItemIndex];
bool valueOK = false;
var txtNewValue = gridViewRow.Cells[COL_NEW_VALUE].FindControl("txtNewValue") as TextBox;
var txtNewDate = gridViewRow.Cells[COL_NEW_DATE].FindControl("txtNewDate") as TextBox;
var labelError = gridViewRow.Cells[COL_NEW_VALUE].FindControl("lblError") as Label;
var labelInfo = gridViewRow.Cells[COL_NEW_VALUE].FindControl("lblStatus") as Label;
labelInfo.Text = string.Empty;
labelError.Text = string.Empty;
rowData.InfoText = string.Empty;
rowData.ErrorText = string.Empty;
rowData.EnteredDateCache = txtNewDate.Text;
rowData.EnteredValueCache = txtNewValue.Text;
if (rowData != null && (!string.IsNullOrEmpty(txtNewValue.Text) || !string.IsNullOrEmpty(txtNewDate.Text)))
{
if (!txtNewValue.Text.IsNumber())
{
rowData.ErrorText = rowData.Name + " must be a number.";
AddCustomValidatorForCell(rowData.ErrorText, gridViewRow, 4);
}
else
{
if (txtNewValue.Text != "100")
{
rowData.ErrorText = rowData.Name + " is invalid.";
AddCustomValidatorForCell(rowData.ErrorText, gridViewRow, 4);
}
else
{
valueOK = true;
}
}
}
}
private void AddCustomValidatorForCell(string errorMessage, GridViewRow gridViewRow, int cellIndex)
{
var labelError = gridViewRow.Cells[cellIndex].FindControl("lblError") as Label;
var divInfoError = gridViewRow.Cells[cellIndex].FindControl("ErrorPanel") as Panel;
labelError.Text = errorMessage;
labelError.ToolTip = errorMessage;
labelError.Attributes.Add("style", "color: red;");
CustomValidator validatePower = new CustomValidator()
{
IsValid = false,
ErrorMessage = errorMessage,
EnableViewState = false,
};
Page.Validators.Add(validatePower);
}
protected void SaveButton_Click(object sender, EventArgs e)
{
SaveData();
this.MyDataGrid.DataSource = ViewState["GridData"];
this.MyDataGrid.DataBind();
}
protected void MyDataGrid_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == System.Web.UI.WebControls.DataControlRowType.DataRow)
{
var rowData = e.Row.DataItem as RowData;
if (rowData != null)
{
DataControlFieldCell txtNewDate = (DataControlFieldCell)e.Row.Cells[COL_NEW_DATE];
DataControlFieldCell txtNewValue = (DataControlFieldCell)e.Row.Cells[COL_NEW_VALUE];
e.Row.Cells[1].Text = rowData.Date.HasValue ? rowData.Date.ToString() : string.Empty;
e.Row.Cells[2].Text = rowData.Value.HasValue ? rowData.Value.Value.ToString() : string.Empty;
txtNewValue.Enabled = txtNewDate.Enabled = (canEdit & rowData.Editable);
if (!string.IsNullOrEmpty(rowData.EnteredDateCache))
txtNewDate.Text = rowData.EnteredDateCache;
if (!string.IsNullOrEmpty(rowData.EnteredValueCache))
txtNewValue.Text = rowData.EnteredValueCache;
(e.Row.FindControl("lblStatus") as Label).Text = rowData.InfoText;
(e.Row.FindControl("lblError") as Label).Text = rowData.ErrorText;
//(e.Row.FindControl("ErrorPanel") as Panel).Visible = (!string.IsNullOrEmpty(rowData.InfoText) || !string.IsNullOrEmpty(rowData.ErrorText));
}
}
}
[Serializable()]
private class RowData
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime? Date { get; set; }
public double? Value { get; set; }
public string ValidationRule { get; set; }
public string ErrorText { get; set; }
public string InfoText { get; set; }
public string EnteredDateCache { get; set; }
public string EnteredValueCache { get; set; }
public bool Editable { get; set; }
}
}
public static class StringExtensionMethods
{
public static bool IsNumber(this String str)
{
double Number;
if (double.TryParse(str, out Number)) return true;
return false;
}
}
【问题讨论】:
标签: asp.net gridview data-binding