Question

I have a RadGrid (Gridview) that has the option to edit and insert new items.

Within both those options i have a customvalidator to check for existing values so duplicates cannot be entered. What i am stuck on is the ability to use findcontrol for the textbox that only is shown during EDIT and INSERT.

This works great for INSERT as i call GetInsertItem(), but that throws an error when editing and i am stuck on that. I want to do this outside of the databound and command methods.

protected void cvAccountNumber_ServerValidate(object source, ServerValidateEventArgs args)
{
    TextBox txtAccountNumber = (TextBox)RadGrid1.MasterTableView.GetInsertItem().FindControl("txtAccountNumber");

    List<GridDataItem> Items = (from item in RadGrid1.Items.Cast<GridDataItem>()
                                where item["AccountNumberView"].Text == txtAccountNumber.Text
                                select item).ToList();

    args.IsValid = Items.Count() == 0;
}

Here is an image of the edit screen. enter image description here

ASPX:

Sort By Status: <asp:DropDownList ID="dd_Status" runat="server" Width="150px" 
    onselectedindexchanged="dd_Status_SelectedIndexChanged" 
    AutoPostBack="True">
    <asp:ListItem Text="All" Value="0" Selected="True"></asp:ListItem>
    <asp:ListItem Text="Active" Value="True"></asp:ListItem>
    <asp:ListItem Text="Inactive" Value="False"></asp:ListItem>
</asp:DropDownList>

<br /><br />

<telerik:RadGrid ID="RadGrid1" runat="server" Skin="Vista" Width="500px"
    GridLines="None" AllowFilteringByColumn="False" AllowSorting="True" OnExportCellFormatting="RadGrid1_ExportCellFormatting" DataSourceID="SqlDataSource1"
     AllowAutomaticDeletes="true" AllowAutomaticUpdates="True" AutoGenerateEditColumn="True"  AutoGenerateDeleteColumn="true" OnItemCommand="RadGrid1_ItemCommand" >
    <MasterTableView AutoGenerateColumns="False" DataKeyNames="ID" DataSourceID="SqlDataSource1" ItemStyle-HorizontalAlign="Left" CommandItemDisplay="TopAndBottom">
        <Columns>
            <telerik:GridTemplateColumn HeaderText="ID" SortExpression="ID" UniqueName="ID" Visible="false" ReadOnly="true"> 
                <ItemTemplate> 
                    <asp:Label ID="lblIDView" runat="server" Text='<%# Bind("ID") %>'></asp:Label> 
                </ItemTemplate> 
            </telerik:GridTemplateColumn>
            <telerik:GridTemplateColumn HeaderText="ID" SortExpression="IDEdit" UniqueName="IDEdit" Visible="false">
                <ItemTemplate />
                <EditItemTemplate>
                    <asp:Label ID="lblID" runat="server" Text='<%# Bind("ID") %>'></asp:Label> 
                </EditItemTemplate>
            </telerik:GridTemplateColumn>
            <telerik:GridBoundColumn DataField="AccountNumber" HeaderText="Sapphire Account Number" 
                SortExpression="AccountNumber" UniqueName="AccountNumberView" ReadOnly="true" ItemStyle-Width="400">
            </telerik:GridBoundColumn>
            <telerik:GridTemplateColumn HeaderText="Sapphire Account Number" SortExpression="AccountNumber" UniqueName="AccountNumber" Visible="false">
                <ItemTemplate />
                <EditItemTemplate>
                    <asp:Textbox ID="txtAccountNumber" runat="server" Text='<%# Bind("AccountNumber") %>' />
                    <asp:RequiredFieldValidator ID="rfvAccountNumber" ControlToValidate="txtAccountNumber"
                        ErrorMessage="Sapphire Account Number is required" runat="server" ForeColor="Red"></asp:RequiredFieldValidator>
                    <asp:CustomValidator ID="cvAccountNumber" runat="server" ErrorMessage="Sapphire Account Number already exists"
                        ControlToValidate="txtAccountNumber" ForeColor="Red" OnServerValidate="cvAccountNumber_ServerValidate"></asp:CustomValidator>
                </EditItemTemplate>
            </telerik:GridTemplateColumn>
            <telerik:GridTemplateColumn HeaderText="Active" SortExpression="Active" UniqueName="Active" ItemStyle-Width="100" Visible="false">
                <ItemTemplate />
                <EditItemTemplate>
                    <asp:CheckBox ID="cbActive" runat="server" Checked='<%# GenerateBindString(Container.DataItem) %>' />
                </EditItemTemplate>
            </telerik:GridTemplateColumn>
            <telerik:GridTemplateColumn HeaderText="Status" SortExpression="Active" UniqueName="Active" ItemStyle-Width="100"> 
                <ItemTemplate> 
                    <asp:Label ID="lblActive" runat="server" Text='<%# Convert.ToBoolean(GenerateBindString(Container.DataItem)) == true ? "Active" : "Inactive" %>'></asp:Label> 
                </ItemTemplate> 
            </telerik:GridTemplateColumn> 
         </Columns>
    </MasterTableView>
    <ValidationSettings CommandsToValidate="PerformInsert,Update" />
    <ClientSettings>
        <Selecting AllowRowSelect="True" />
    </ClientSettings>
</telerik:RadGrid>

<asp:SqlDataSource ID="SqlDataSource1" runat="server" 
    ConnectionString="<%$ ConnectionStrings:LBCust %>" 
    SelectCommand="SELECT * FROM [LBX_Portal_AccountNumbers] WHERE ([Site] = @Site) AND (Active=@Active OR @Active = '0') ORDER BY AccountNumber"
    DeleteCommand="DELETE FROM [LBX_Portal_AccountNumbers] WHERE [ID] = @ID" 
    InsertCommand="INSERT INTO [LBX_Portal_AccountNumbers] ([AccountNumber], [Site], [Active]) VALUES (@AccountNumber, @Site, @Active)" 
    UpdateCommand="UPDATE [LBX_Portal_AccountNumbers] SET [AccountNumber] = @AccountNumber,  [Active] = @Active WHERE [ID] = @ID">
    <SelectParameters>
        <asp:ControlParameter ControlID="dd_Status" Name="Active" 
            PropertyName="SelectedValue" Type="String" />
    </SelectParameters>
    <DeleteParameters>
        <asp:Parameter Name="ID" Type="Int32" />
    </DeleteParameters>
    <InsertParameters>
        <asp:Parameter Name="AccountNumber" Type="String" />
        <asp:Parameter Name="Site" Type="String" />
        <asp:Parameter Name="Active" Type="Boolean" />
    </InsertParameters>
    <UpdateParameters>
        <asp:Parameter Name="AccountNumber" Type="String" />
        <asp:Parameter Name="Active" Type="Boolean" />
    </UpdateParameters>
</asp:SqlDataSource>

CS:

public partial class Admin_CustomerAccountManager : System.Web.UI.Page
{
public string SiteName = WebConfigurationManager.AppSettings["Site"].ToString();

protected void Page_Load(object sender, EventArgs e)
{
    Label LBXTitle = (Label)Master.FindControl("lbxTitle");

    LBXTitle.Text = "Customer Sapphire Account Number Manager";

    if (!this.IsPostBack)
    {
        SqlDataSource1.SelectParameters.Add("Site", DbType.String, SiteName);
    }
}

protected void dd_Status_SelectedIndexChanged(object sender, EventArgs e)
{
    RadGrid1.DataBind();
}

protected bool GenerateBindString(object dataItem)
{
    bool ret = false;
    // if column is null set checkbox.checked = false

    if ((DataBinder.Eval(dataItem, "Active")).ToString() == "")
        ret = false;
    else // set checkbox.checked to boolean value in Status column
        ret = (bool)DataBinder.Eval(dataItem, "Active");

    return ret;
}

protected void RadGrid1_ItemCommand(object source, Telerik.Web.UI.GridCommandEventArgs e)
{
    Page.Validate();
    if (Page.IsValid)
    {
        if (e.CommandName == "PerformInsert")
        {
            GridEditFormItem gridEditFormItem = (GridEditFormItem)e.Item;

            Label lblID = (Label)gridEditFormItem.FindControl("lblID");
            TextBox txtAccountNumber = (TextBox)gridEditFormItem.FindControl("txtAccountNumber");
            CheckBox cbActive = (CheckBox)gridEditFormItem.FindControl("cbActive");

            bool isActive = true;

            string SqlStr = "INSERT INTO [LBX_Portal_AccountNumbers] ([AccountNumber], [Site], [Active])";
            SqlStr += " VALUES ('" + txtAccountNumber.Text + "'" + ", '" + SiteName + "'" + ", '" + isActive + "')";

            SqlDataSource1.InsertCommand = SqlStr;
            SqlDataSource1.Insert();

        }

        if (e.CommandName == "Update")
        {
            GridEditFormItem gridEditFormItem = (GridEditFormItem)e.Item;

            Label lblID = (Label)gridEditFormItem.FindControl("lblID");
            TextBox txtAccountNumber = (TextBox)gridEditFormItem.FindControl("txtAccountNumber");
            CheckBox cbActive = (CheckBox)gridEditFormItem.FindControl("cbActive");

            bool isActive = false;

            if (cbActive.Checked)
                isActive = true;
            else
                isActive = false;

            string SqlStr = "UPDATE [LBX_Portal_AccountNumbers] SET [AccountNumber] = '" + txtAccountNumber.Text;
            SqlStr += "', [Active] = '" + isActive + "'  WHERE [ID] = " + lblID.Text;

            SqlDataSource1.UpdateCommand = SqlStr;
            SqlDataSource1.Update();
        }
    }
}

protected void cvAccountNumber_ServerValidate(object source, ServerValidateEventArgs args)
{
    TextBox txtAccountNumber = RadGrid1.FindControl("txtAccountNumber") as TextBox;
    List<GridDataItem> Items = (from item in RadGrid1.Items.Cast<GridDataItem>()
                                where item["AccountNumberView"].Text == txtAccountNumber.Text
                                select item).ToList();

    args.IsValid = Items.Count() == 0;
}
}
Was it helpful?

Solution

It looks that GridView.FindControl inside validate event never works, how ever you can access string that needs to be validated like this:

This is how you validate target control value:

    protected void cvAccountNumber_ServerValidate(object source, ServerValidateEventArgs args)
    {
        string textToBeValidated = args.Value;
    }

And here is how you can access actual controls. GridView.FindControl will end up with nothing when using inside ServerValidate context, so you have to look inside edited/inserted row.

    protected void cvAccountNumber_ServerValidate(object source, ServerValidateEventArgs args)
    {
        //find your editing row...
        GridViewRow editedRow = RadGrid1.Rows[RadGrid1.EditIndex];
        //now serch row for your control...
        TextBox txtAccountNumber = (TextBox)editedRow.FindControl("txtAccountNumber");
        TextBox txtId = (TextBox)editedRow.FindControl("txtId");
    }

OTHER TIPS

First of all your code is prone to SQL injection, but it's not your initial question.

You cannot loop through GridDataItems to find duplicate. You won't be able to find it if you later paginate your grid.

At first, you can use InsertCommand and UpdateCommand events of RadGrid for simplicity. Then check the duplicate using ADO.Net or whatever method you prefer.

protected void RadGrid1_InsertCommand(object source, GridCommandEventArgs e)
{
   try
   {
      var gridEditFormItem = (GridEditFormItem) e.Item;

      var txtAccountNumber = (TextBox)gridEditFormItem.FindControl("txtAccountNumber"); 
      var cbActive = (CheckBox)gridEditFormItem.FindControl("cbActive"); 

      // TODO: Check duplicate against database

      string SqlStr = "INSERT INTO [LBX_Portal_AccountNumbers] ([AccountNumber], [Site], [Active])" + 
        " VALUES ('" + txtAccountNumber.Text + "'" + ", '" + SiteName + "'" + ", '" + isActive + "')"; 

      SqlDataSource1.InsertCommand = SqlStr; 
      SqlDataSource1.Insert(); 

   }
   catch (Exception ex)
   {
      // Log Error
   }
}

protected void RadGrid1_UpdateCommand(object source, GridCommandEventArgs e)
{
   try
   {
      var gridEditFormItem = (GridEditFormItem) e.Item;

      int id = Convert.ToInt32(e.Item.OwnerTableView.DataKeyValues[e.Item.ItemIndex]["ID"]);
      var txtAccountNumber = (TextBox)gridEditFormItem.FindControl("txtAccountNumber"); 
      var cbActive = (CheckBox)gridEditFormItem.FindControl("cbActive"); 

      // TODO: Check duplicate against database

      string SqlStr = "UPDATE [LBX_Portal_AccountNumbers] SET [AccountNumber] = '" + txtAccountNumber.Text + 
         "', [Active] = '" + isActive + "'  WHERE [ID] = " + lblID.Text; 

      SqlDataSource1.UpdateCommand = SqlStr; 
      SqlDataSource1.Update(); 

   }
   catch (Exception ex)
   {
      // Log Error
   }
}

This is what I would suggest and how to takle this issue.

Put a break point in the code where you are getting error.

Run the program that is Debug. The program will stop at the break point.

In the Watch Windows add your object and see what values it contains. Do not be afraid. Watch Window is very powerful. You can add an object or any of its property to see what value it contains. You specifically want to focus on null value.

Once you identify the null exception where it is coming from, fix that syntax right in the Watch window and run the program again.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top