【问题标题】:dealing with GridView and Custom Validation, both client and serverside处理客户端和服务器端的 GridView 和自定义验证
【发布时间】:2021-08-01 09:01:57
【问题描述】:

我不太确定如何解决这个问题。

我正在尝试做的事情: 浏览具有多行的网格视图,如果某些文本框或下拉列表保留在默认值上,则强制用户输入特定值。

我尝试了什么:

  1. 通过使用 javascript 中的 focusout 事件尝试了客户端要求。根据用户之前所做的选择,焦点会转移到这些字段上,这部分是有效的。我的代码:
var row = $(this).closest('tr');
var text = $(row).find("input[name*='txtCurriculum']").val('enter lesson/unit name here'); 
var ddl = $(row).find("select[name*='ddlCurrAdditions']");
$(ddl).focusout(function () {
    if (ddl.val == "-select curriculum name-") {
        $(ddl).focus();
        alert("select a curriculum name before moving on");
    }
});

$(text).focusout(function () {
    if (text.val == 'enter lesson/unit name here') {
        $(text).focus();
        alert('enter in a lesson or unit name before moving on');
    }
});

它从未正确发射。 ddl focusout 会触发,但在我退出并返回页面之前不会停止触发。 text focusout 永远不会触发。

  1. 尝试使用自定义验证功能进行服务器端验证。
protected void cv1_ServerValidate(object source, ServerValidateEventArgs args)
{
    CustomValidator cv = ((CustomValidator)(source));
    GridViewRow gvr;

    //if (FormCGrid.Rows)
    foreach (GridViewRow row in FormCGrid.Rows)
    {
        //string ddl = ((DropDownList)row.FindControl("ddlCurrAdditions")).SelectedItem.Text;

        string txtC = ((TextBox)row.FindControl("txtCurriculum")).Text;
        bool ddl = ((DropDownList)row.FindControl("ddlCurrAdditions")).Visible;

        if (txtC == "enter lesson/unit name here")
        {
            args.IsValid = false;
            cv.ErrorMessage = string.Format("Please enter the Additional program name on row {0}", row.RowIndex);      
        }
        else if (ddl == true)
        {
            cv.ErrorMessage = string.Format("Enter your lesson or unit for the curriculum selected on row  {0}", row.RowIndex);
            args.IsValid = false;
        }
    }
}

我试图在这里遍历 gridview 的行,检查命名下拉列表的可见性(隐藏直到另一个下拉列表显示它,取决于那里选择的值)和默认值的文本框,但这也不起作用.它根本没有开火。欢迎提出任何建议。

我通常可以解决大多数编程/编码问题,但我发现使用 asp.net gridview 时,我的所有技术都被抛到了窗外。

【问题讨论】:

  • 何时应进行此验证?如果单击按钮,则在第一种方法上,您应该覆盖单击方法。在第二种方法中,您没有指定遇到什么问题。
  • 验证应该在用户点击保存时进行。进行编辑以告知方法 2 发生的情况。

标签: c# asp.net validation gridview customvalidator


【解决方案1】:

好的,有两种方法可以做到这一点,在这里你可以很容易地使用js。但是,让我们使用 100% 的服务器端代码。我认为坚持使用服务器端代码更容易。

下一个?实际上,当您计划编辑数据时,我建议使用列表视图代替网格视图。原因很简单——ListView 不需要那些“令人讨厌的”“项目模板”一遍又一遍地为您想要在该网格显示中删除/拥有的每个 asp.net 控件。现在公平地说,说 2-3 个控件 - 然后网格视图是可以的,但是更多,然后我真的发现列表视图开始在这里赢得很大的时间(不需要项目模板)。 listview的“诀窍”当然是在网页上设置一个数据源,让它生成标记,然后吹出(删除)除项目模板之外的所有模板。然后删除页面上的datasource1项,并从列表视图中删除datasource1设置。

但是,让我们使用网格视图 - 因此这将是一些“更混乱”的东西

所以,我们要填写网格 - 并说我们想要一个城市组合框 - 必须选中。让我们进行基本检查,说 LastName 也必须输入。

所以,我们有一个城市组合框(数据库驱动)。假设让我们在一个下拉列表中折腾酒店评级(1-5)——但这只有 5 个选择——所以我们有那个带有标记列表的下拉列表。 (所以两个组合示例来说明这是如何工作的)。

所以,假设我们有一个这样的网格,然后我们点击保存,我们会得到这个结果:

现在,我们当然会喜欢那个消息框区域。事实上,我们可以很容易地放入 jQuery.UI 并让右边那个可爱的 div 出现在一个对话框中(我们甚至可以从我们后面的服务器端代码触发那个框 + jQuery.UI 对话框显示 - 但让我们试试并保持简短 - 但我会喜欢那个错误消息区域)。

好的,首先是标记:

只是一个简单的网格,但由于那些“项目模板”而“有点混乱” - (如果你不明白这一点,我真的不喜欢那些模板的东西!!! - 使用列表视图你不需要它们!! - 只需为网格添加纯干净的 asp.net 控件)。无论如何:

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ID">
    <Columns>

        <asp:BoundField DataField="ID" HeaderText="ID" InsertVisible="False" ReadOnly="True" SortExpression="ID" />
                
        <asp:TemplateField  HeaderText="HotelName" >
            <ItemTemplate><asp:TextBox id="HotelName" runat="server" Text='<%# Eval("HotelName") %>' /></ItemTemplate>
        </asp:TemplateField>

        <asp:TemplateField  HeaderText="FirstName" >
            <ItemTemplate><asp:TextBox id="FirstName" runat="server" Text='<%# Eval("FirstName") %>' /></ItemTemplate>
        </asp:TemplateField>

        <asp:TemplateField  HeaderText="LastName" >
            <ItemTemplate><asp:TextBox id="LastName" runat="server" Text='<%# Eval("LastName") %>' /></ItemTemplate>
        </asp:TemplateField>

        <asp:TemplateField HeaderText="City">
            <ItemTemplate>
                <asp:DropDownList ID="cboCity" runat="server" DataTextField="City" 
                    DataValueField = "City" Width="110px">
                </asp:DropDownList>
            </ItemTemplate>
        </asp:TemplateField>

        <asp:TemplateField HeaderText="Active">
            <ItemTemplate><asp:CheckBox id="Active" runat="server"  Checked = '<%# Eval("Active") %>'  /></ItemTemplate>
        </asp:TemplateField>

        <asp:TemplateField HeaderText="Rating">
            <ItemTemplate>
                <asp:DropDownList ID="cboRating" runat="server" SelectedValue = '<%# Eval("Rating") %>' >
                    <asp:ListItem Value="1">Poor</asp:ListItem>
                    <asp:ListItem Value="2">Just Ok</asp:ListItem>
                    <asp:ListItem Value="3">Ok</asp:ListItem>
                    <asp:ListItem Value="4">Good</asp:ListItem>
                    <asp:ListItem Value="5">Excellent</asp:ListItem>
                </asp:DropDownList>
            </ItemTemplate>
        </asp:TemplateField>
         
    </Columns>

</asp:GridView>
</div>

    <div id="ErrorDialog" style="display:normal;float:left;padding-left:30px;width:20%" runat="server">
        <asp:TextBox ID="txtErrors" runat="server" TextMode="MultiLine" Style="width:100%" Rows="20"   ></asp:TextBox>
    </div>

<div style="clear:both;padding-top:20px">
    <asp:Button ID="cmdSave" runat="server" Text="Save" />
    <asp:Button ID="cmdUnDo" runat="server" Text="UnDo" Style="margin-left:20px"/>
</div>

好的,现在开始了吗?哎呀,这大约是我一次发布的最大标记总数 - 超出上述范围,我们接近“不太好”的帖子领域。

好的,让我们看看加载这个网格的代码。我们有这个代码:

public class EditHotelsG : System.Web.UI.Page
{
private DataTable rstTable = new DataTable();
private DataTable rstCity = new DataTable();

protected void Page_Load(object sender, System.EventArgs e)
{
    if (System.Web.UI.Page.IsPostBack == false)
    {
        ErrorDialog.Visible = false;

        LoadGrid();
        ViewState["rstTable"] = rstTable;
        ViewState["rstCity"] = rstCity;
    }
    else
    {
        rstTable = ViewState["rstTable"];
        rstCity = ViewState["rstCity"];
    }
}


public void LoadGrid()
{

    // load up our drop down list from database (city)
    string strSQL;

    strSQL = "SELECT City from tblCity Order by City";

    using (SqlCommand cmdSQL = new SqlCommand(strSQL, new SqlConnection(My.Settings.TEST3)))
    {
        cmdSQL.Connection.Open();

        rstCity.Load(cmdSQL.ExecuteReader);

        // now load up main grid view

        strSQL = "SELECT ID, FirstName, LastName, HotelName, City, Active, Rating from tblHotels ORDER BY HotelName";

        cmdSQL.CommandText = strSQL;

        rstTable.Load(cmdSQL.ExecuteReader);
        GridView1.DataSource = rstTable;
        GridView1.DataBind();
    }
}


protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{

    // set combo box data source
    if (e.Row.RowType == DataControlRowType.DataRow)
    {

        // setup city drop down list

        DropDownList cboDrop = e.Row.FindControl("cboCity");
        cboDrop.DataSource = rstCity;
        cboDrop.DataBind();
        cboDrop.Items.Insert(0, new ListItem(string.Empty));     // add blank row

        cboDrop.Text = rstTable.Rows(e.Row.RowIndex).Item("City").ToString;
    }
}
}

好的,现在代码不多了。一个很好的部分是设置组合框。由于 cbo 框(下拉列表)是数据库驱动的,因此我们必须为每一行绑定 + 设置。因此,这花费了我们大量的编码时间。

但是请注意我们如何持久化数据库源(表)。我们这样做,因为我们想要使用 A LOT LESS 代码,所以一次更新整个数据库。通过持久化该表,然后我们

Transfer data from Grid to table
Save the table to database in one shot

因此,这减少了我们的编码工作量。

保存数据的代码,因此变成了这个 gem: (并注意我们如何输入验证代码)。

protected void cmdSave_Click(object sender, EventArgs e)
{

// pull gride rows back to table.
bool bolDataOk = true;
txtErrors.Text = "";

foreach (GridViewRow rRow in GridView1.Rows)
{
    int RecordPtr = rRow.RowIndex;

    DataRow OneDataRow;
    OneDataRow = rstTable.Rows(RecordPtr);

    OneDataRow.Item("HotelName") = rRow.FindControl("HotelName") as TextBox.Text;
    OneDataRow.Item("FirstName") = rRow.FindControl("FirstName") as TextBox.Text;
    OneDataRow.Item("LastName") = rRow.FindControl("LastName") as TextBox.Text;
    OneDataRow.Item("City") = rRow.FindControl("cboCity") as DropDownList.Text;
    OneDataRow.Item("Active") = rRow.FindControl("Active") as CheckBox.Checked;
    OneDataRow.Item("Rating") = rRow.FindControl("cboRating") as DropDownList.SelectedValue;

    // check for missing City, or LastName
    if (IsDBNull(OneDataRow("City")) | OneDataRow("City") == "")
    {
        bolDataOk = false;
        if (txtErrors.Text != "")
            txtErrors.Text += Constants.vbCrLf;
        txtErrors.Text += "Missing City on row = " + (rRow.RowIndex + 1).ToString;
    }

    if (IsDBNull(OneDataRow("LastName")) | OneDataRow("LastName") == "")
    {
        bolDataOk = false;
        if (txtErrors.Text != "")
            txtErrors.Text += Constants.vbCrLf;
        txtErrors.Text += "Missing lastName on row = " + (rRow.RowIndex + 1).ToString;
    }
}

ErrorDialog.Visible = !(bolDataOk);

// now send table back to database with updates

if (bolDataOk)
{
    string strSQL = "SELECT ID, FirstName, LastName, City, HotelName, Active, Rating from tblHotels WHERE ID = 0";
    using (SqlCommand cmdSQL = new SqlCommand(strSQL, new SqlConnection(My.Settings.TEST3)))
    {
        cmdSQL.Connection.Open();
        SqlDataAdapter daupdate = new SqlDataAdapter(cmdSQL);
        SqlCommandBuilder cmdBuild = new SqlCommandBuilder(daupdate);

        daupdate.Update(rstTable);
    }
}
}

现在,再一次,上面的代码片段有点长 - 并且是 SO 的代码片段的最大大小。我可能会考虑将上面最后的代码分解为 2 个甚至 3 个例程。

但是,总而言之,上面展示了相当多的技巧和方法。

如前所述,我将发布您如何/可以使用客户端代码进行验证,但是通过一次数据库更新来保存整个网格的全部想法?好吧,我会将这个技巧与 listview、gridview 一起使用,即使我正在做客户端 js 验证?我仍然会使用上面的大部分设计模式。

还有撤消按钮?好吧,我从来没有完成那部分 - 但它只会调用与第一页加载相同的代码(回发 - 错误,您只需从数据库源重新绑定网格以获得撤消按钮。

【讨论】:

    猜你喜欢
    • 2017-05-03
    • 2010-10-16
    • 1970-01-01
    • 2016-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-17
    • 2023-04-08
    相关资源
    最近更新 更多