I have a databound textbox within a gridview which enables the user to easily and quickly bulk update rows. I have tried to use the CustomValidator to validate each textbox against a SQL column but it doesn't behave the way I need it to. The CustomValidator code works properly in the TextChanged event, however it does not behave properly in the ServerValidate event (I understand why). If I leave the code in the TextChanged event handler it still allows the data to be modified when hitting the Update button I created. What can I do to validate each TextBox individually and effectively against the SQL data?
<ItemTemplate>
<asp:TextBox ID="Account" runat="server" AutoPostBack="true" OnTextChanged="Account_TextChanged" Text='<%# Bind("Account") %>'></asp:TextBox>
<asp:CustomValidator ID="CustomValidator1" runat="server" CssClass="CustomValidator" ValidateEmptyText="false" SetFocusOnError="True" Display="Dynamic" ControlToValidate="Account" OnServerValidate="Validate_ServerValidate" ErrorMessage="Custom Validator"></asp:CustomValidator>
</ItemTemplate>
foreach (GridViewRow row in GridView2.Rows)
{
TextBox Account = row.FindControl("Account") as TextBox;
CustomValidator validator = row.FindControl("CustomValidator1") as CustomValidator;
string sAccount = Account.Text;
using (SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["ConnString"].ConnectionString))
using (SqlDataAdapter da = new SqlDataAdapter("SELECT Account Table WHERE Account = #Account", conn))
{
da.SelectCommand.Parameters.Add("#Account", SqlDbType.VarChar);
da.SelectCommand.Parameters["#Account"].Value = sAccount;
DataSet ds = new DataSet();
da.Fill(ds);
if (ds.Tables[0].Rows.Count > 0)
{
validator.IsValid = true;
}
else
{
validator.IsValid = false;
}
}
}
I think you would want to do something like
Front Page:
<asp:TextBox runat="server" ID="txtValidateMe"></asp:TextBox>
<asp:CustomValidator runat="server" id="validateTheTextBox" OnServerValidate="validateTheTextBox_OnServerValidate" ControlToValidate="txtValidateMe"/>
Server Side
protected void Page_Load(object sender, EventArgs e)
{
Page.Validate();
if (Page.IsValid)
{
//do something
}
}
protected void validateTheTextBox_OnServerValidate(object source, ServerValidateEventArgs args)
{
using (var conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["ConnString"].ConnectionString))
using (var da = new SqlDataAdapter("SELECT Account Table WHERE Account = #Account", conn))
{
da.SelectCommand.Parameters.Add("#Account", SqlDbType.VarChar);
da.SelectCommand.Parameters["#Account"].Value = args.Value;
DataSet ds = new DataSet();
da.Fill(ds);
if (ds.Tables[0].Rows.Count > 0)
{
args.IsValid = true;
}
else
{
args.IsValid = false;
}
}
}
hope this helps
I was able to get this handled by moving the validation logic out of the ServerValidate Event and into an update buttonclick event.
protected void update_Click(object sender, EventArgs e)
{
foreach (GridViewRow row in SomeGrid.Rows)
{
TextBox SomeTextBox = row.FindControl("SomeTextBox") as TextBox;
CustomValidator validator = row.FindControl("SomeValidator") as CustomValidator;
string Account = SomeTextBox.Text;
using (SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString))
using (SqlDataAdapter da = new SqlDataAdapter("SELECT Account FROM Account WHERE Account = #Account", conn))
{
da.SelectCommand.Parameters.Add("#Account", SqlDbType.VarChar);
da.SelectCommand.Parameters["#Account"].Value = Account;
DataSet ds = new DataSet();
da.Fill(ds);
if (ds.Tables[0].Rows.Count > 0)
{
validator.IsValid = true;
}
else
{
validator.IsValid = false;
}
}
}
}
Related
So basically i want to create a booking and a booking can have multiple orders but i dont know how to store the orders that have been selected in the other pages etc. but I already know i have to do a cycle to run the gridview bue i dont know how to do that with a pager and with a search textbox.
this is how it looks:
Current CS
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Configuration;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace Gestão_de_embarques
{
public partial class CriarEcomenda : System.Web.UI.Page
{
SqlConnection con = new SqlConnection(WebConfigurationManager.ConnectionStrings["constring"].ConnectionString);
protected void Page_Load(object sender, EventArgs e)
{
con.Open();
string user = Convert.ToString(Session["user"]);
username.Text = user;
if (Session["user"] == null || Session["login"] == null)
{
Response.Redirect("Login.aspx", false);
}
if (!Page.IsPostBack)
{
refreshdata();
}
con.Close();
}
public void refreshdata()
{
SqlCommand cmd = new SqlCommand("select DISTINCT No_ from [Encomenda]", con);
SqlDataAdapter sda = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
sda.Fill(dt);
GridView1.DataSource = dt;
GridView1.DataBind();
}
protected void btnsearch_Click(object sender, EventArgs e)
{
con.Open();
if (txtSearch.Value == "")
{
refreshdata();
}
else
{
try
{
SqlCommand cmd = new SqlCommand("select DISTINCT No_ from [encomenda] where No_= #No_", con);
cmd.Parameters.Add("#No_", SqlDbType.NVarChar).Value = txtSearch.Value;
SqlDataReader sdr = cmd.ExecuteReader();
if (sdr.Read())
{
sdr.Close();
SqlDataAdapter sda = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
sda.Fill(dt);
GridView1.DataSource = dt;
GridView1.DataBind();
con.Close();
}
else
{
SqlDataAdapter sda = new SqlDataAdapter(cmd);
sdr.Close();
DataTable dt = new DataTable();
sda.Fill(dt);
GridView1.DataSource = dt;
GridView1.DataBind();
ButtonCreate.Visible = false;
}
}
catch(Exception ex)
{
}
}
}
protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
GridView1.PageIndex = e.NewPageIndex;
refreshdata();
}
}
}
Well, if you were not data paging, then the un-bound check box would persist and survive even post backs.
But, since you have data paging? Then you persist the selected PK id from the database. (you don't have to display the pk row, but just set DataKeys = "ID" or what ever your PK row is from the database.
As noted, with searching and paging, you have to re-bind the grid, so you can't use the grid to persist the selected check boxes. Say we have a list of hotels to select.
Our markup would be this:
<div style="width:40%">
<asp:GridView ID="MyGrid" runat="server" CssClass="table table-hover"
DataKeyNames="ID" AutoGenerateColumns="false" OnRowDataBound="MyGrid_RowDataBound" >
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="Last Name" />
<asp:BoundField DataField="HotelName" HeaderText="Hotel Name" />
<asp:BoundField DataField="HotelName" HeaderText="Hotel Name" />
<asp:BoundField DataField="Province" HeaderText="Province" />
<asp:TemplateField HeaderText="Select">
<ItemTemplate>
<asp:CheckBox ID="CheckBox1" runat="server" OnCheckedChanged="CheckBox1_CheckedChanged" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:Button ID="Button1" runat="server" Text="Show Selected rows" OnClick="Button1_Click" />
<br />
<br />
</div>
And code to load up this grid would be:
List<int> MySelected = new List<int>();
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack == false)
{
LoadGrid();
ViewState["MySelected"] = MySelected;
}
else
{
MySelected = (List<int>)ViewState["MySelected"];
}
}
public void LoadGrid()
{
using (SqlCommand cmdSQL = new SqlCommand("SELECT * from tblHotels ORDER BY HotelName",
new SqlConnection(Properties.Settings.Default.TEST3)))
{
cmdSQL.Connection.Open();
DataTable rst = new DataTable();
rst.Load(cmdSQL.ExecuteReader());
MyGrid.DataSource = rst;
MyGrid.DataBind();
}
}
protected void MyGrid_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
int PkRow = (int)((DataRowView)e.Row.DataItem)["ID"];
CheckBox ckbox = (CheckBox)e.Row.FindControl("CheckBox1");
if (MySelected.Contains(PkRow)) {
ckbox.Checked = true;
}
}
}
protected void CheckBox1_CheckedChanged(object sender, EventArgs e)
{
CheckBox ckBox = (CheckBox)sender;
GridViewRow gvRow = (GridViewRow)ckBox.Parent.Parent;
int RowPK = (int)(MyGrid.DataKeys[gvRow.RowIndex]["ID"]);
if (ckBox.Checked)
MySelected.Add(RowPK);
else
MySelected.Remove(RowPK);
}
Now how I just created a simple list. When you check a box, you simply add the PK row from the GridRow "PK" to the list.
The code to get/work the "list" from the database thus will look like this:
protected void Button1_Click(object sender, EventArgs e)
{
string MyPkList = string.Join(",", MySelected);
string strSQL = "SELECT * from tblHotels where ID IN(" + MyPkList + ")";
using (SqlCommand cmdSQL = new SqlCommand(strSQL, new SqlConnection(Properties.Settings.Default.TEST3)))
{
cmdSQL.Connection.Open();
DataTable rstPickList = new DataTable();
rstPickList.Load(cmdSQL.ExecuteReader());
foreach (DataRow OneRow in rstPickList.Rows)
{
Response.Write("<h2> PK = " + OneRow["Id"].ToString() + " Hotel Name = " + OneRow["HotelName"] + "</h2>");
}
}
}
So, if I check say 3 rows, and hit that button, you get this:
this does mean that you have to set the check box to auto post back. And that thus means for a check box click, you do post-back. However, you could drop the whole grid in a update panel if you need to only post back that grid selecting part and not the whole page.
Once you have that list of PK values from the database, then as the button shows, we have to process against the database table, and we can't use the grid due to paging. As noted, if the gridview could fit on one page, then you would not need the persisting code, and you could just loop the grid view to get the checked rows - you would not need ANY code to persist the values.
After some lengthy experimentation, I discovered that having this line of code on the aspx side:
<EditItemTemplate>
<asp:DropDownList ID="ddl_Project_Owner" runat="server" Width="70px"
DataTextField="Project_Owner" DataValueField="Project_Owner"
SelectedValue='<%# Bind("Project_Owner") %>' >
</asp:DropDownList>
</EditItemTemplate>
caused an index error, but removing the SelectedValue='<%# Bind("Project_Owner") %>' piece allowed the gridview to function properly. The only thing is, when the row goes into edit mode, the dropdown is not filled with the current value. It's blank. I'd like to fill it with the current value.
On the code-behind side, I use this code to fill the dropdown:
protected void DataGrid_ResourceAllocation_EditCommand(object sender, GridViewEditEventArgs e)
{
DataGrid_ResourceAllocation.EditRowStyle.BackColor = System.Drawing.Color.LightYellow;
DataGrid_ResourceAllocation.EditIndex = e.NewEditIndex;
LoadResourceAllocationGrid();
//DataGrid_ResourceAllocation.DataBind();
SqlConnection conn = GetConnection();
int RAC = DataGrid_ResourceAllocation.Rows.Count;
GridViewRow row = DataGrid_ResourceAllocation.Rows[e.NewEditIndex];
//*********************************************************
//******** Fill in all your dropdown lists here ***********
//*********************************************************
DropDownList ddList = row.FindControl("ddl_Project_Owner") as DropDownList;
string ddListVal = ddList.SelectedValue;
//DropDownList ddList = (DropDownList)e.Row.FindControl("ddl_Project_Owner");
if (ddList != null)
{
//bind dropdown-list
string sqlStr = "Select distinct Project_Owner from tblProjectHealth order by Project_Owner";
DataSet ds = new DataSet();
conn.Open();
SqlCommand cmd = new SqlCommand(sqlStr, conn);
SqlDataAdapter ad = new SqlDataAdapter(cmd);
ad.Fill(ds);
ddList.DataSource = ds;
ddList.DataTextField = "Project_Owner";
ddList.DataValueField = "Project_Owner";
ddList.DataBind();
//DataRowView dr = e.Row.DataItem as DataRowView;
//ddList.SelectedItem.Text = dr["category_name"].ToString();
ddList.SelectedValue = ddListVal;
}
}
I tried that "ddListVal" variable because I thought it might work, but it didn't, so you can ignore that.
Can anyone help me get my dropdown to populate with the current value that exists for that field in that record?
This error is due to this : you set selectedValeue befor binding dropdownlist.
you can bind dropdownlist in RowDataBound
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DropDownList ddList= e.Row.FindControl("ddl_Project_Owner") as DropDownList;
if (ddList != null)
{
string sqlStr = "Select distinct Project_Owner from tblProjectHealth order by Project_Owner";
DataSet ds = new DataSet();
conn.Open();
SqlCommand cmd = new SqlCommand(sqlStr, conn);
SqlDataAdapter ad = new SqlDataAdapter(cmd);
ad.Fill(ds);
ddList.DataSource = ds;
ddList.DataTextField = "Project_Owner";
ddList.DataValueField = "Project_Owner";
ddList.DataBind();
}
}
}
I am new to ASP.NET, but I need to create checkboxes from a query result. So far here is what I have.
In my code behind...I pull the query that I need and then create a DataTable from that result like so:
DataTable dtLocations = new DataTable();
dtLocations.Columns.Add("ID");
dtLocations.Columns.Add("VALUE");
// Pull locations and add to our datatable
string strConnection = ConfigurationManager.ConnectionStrings["connString"].ConnectionString;
using (SqlConnection dbConn = new SqlConnection(strConnection))
{
SqlDataAdapter dbAdapter = new SqlDataAdapter();
SqlCommand dbCommand = new SqlCommand();
dbConn.Open();
dbCommand.CommandText = #"SELECT location_id, location_desc FROM admin_locations WHERE enabled = 'Y'";
dbCommand.Connection = dbConn;
SqlDataReader dbReader = dbCommand.ExecuteReader(CommandBehavior.CloseConnection);
if (dbReader.HasRows) {
while (dbReader.Read()) {
dtLocations.Rows.Add(new object[] { dbReader["location_id"].ToString(), dbReader["location_desc"].ToString() });
}
}
}
return dtLocations;
I then have a class level var defined as
public DataTable dtLocations = new DataTable();
which I populate using the method above in my Page_Load
protected void Page_Load(object sender, EventArgs e)
{
if (!(IsPostBack))
{
dtLocations = createLocationsDataTable();
}
}
Then in my aspx file (not code behind) I'm doing this to try and create the checkboxes, which needless to say, does not work.
<% foreach (DataRow row in dtLocations.Rows) {%>
<asp:CheckBox ID="idLocationChk" runat="server" Value="<% Response.Write(row["ID"].ToString()); %>" />
<% } %>
Can someone show me how you're supposed to do this in ASP.NET c#? I'll also need to be able to get the value of any that are checked in my code behind when a button on the page is clicked.
When I try using a CheckBoxList like this it tells me I can not use codeblocks here.
<asp:CheckBoxList ID="message_locations" runat="server">
<% foreach (DataRow row in dtLocations.Rows) {%>
<asp:ListItem>TEST</asp:ListItem>
<% } %>
</asp:CheckBoxList>
You can bind a DataTable directly to a CheckBoxList
if (!IsPostBack)
{
CheckBoxList1.DataSource = dtLocations;
CheckBoxList1.DataTextField = "location_desc";
CheckBoxList1.DataValueField = "location_id";
CheckBoxList1.DataBind();
}
I know I can use the below syntax to validate the field txtfirstname against the database, but what if I needed to take it a step further and validate both txtfirstname and txtlastname against the database, what would I tweak in order to only present an error if BOTH values alreadyd exist in the database?
<asp:TextBox ID="txtfirstname" runat="server"></asp:TextBox><br />
<asp:CustomValidator ID="CustomValidator1" runat="server" ControlToValidate="txtfirstname"
ErrorMessage="Please input a valid first name" Height="21px" OnServerValidate="CustomValidator1_ServerValidate"
Width="154px">Please input first name</asp:CustomValidator><br />
protected void CustomValidator1_ServerValidate(object source, ServerValidateEventArgs args)
{
args.IsValid = false;
string fname = txtfirstname.Text;
SqlConnection conn = new SqlConnection(strCon);
SqlDataAdapter da = new SqlDataAdapter("select * from usertable where usertable.firstname=#fn", conn);
da.SelectCommand.Parameters.Add("#fn");
da.SelectCommand.Parameters["#fn"].Value = fname;
DataSet ds = new DataSet();
da.Fill(ds);
if (ds.Tables[0].Rows.Count > 0)
args.IsValid = true;
}
Simply retrieve the value for the last name field and do the same validation as you are doing it for the first name:
protected void CustomValidator1_ServerValidate(object source, ServerValidateEventArgs args)
{
args.IsValid = false;
string fname = txtfirstname.Text;
string lname = txtlastname.Text; // Get the last name
SqlConnection conn = new SqlConnection(strCon);
SqlDataAdapter da = new SqlDataAdapter("select * from usertable where usertable.firstname=#fn and usertable.lastname=#ln", conn); // Add last name to query
da.SelectCommand.Parameters.Add("#fn");
da.SelectCommand.Parameters["#fn"].Value = fname;
da.SelectCommand.Parameters.Add("#ln"); // New parameter.
da.SelectCommand.Parameters["#ln"].Value = lname;
DataSet ds = new DataSet();
da.Fill(ds);
if (ds.Tables[0].Rows.Count > 0)
args.IsValid = true;
}
Please note that I updated your code and I suppose the name of the last name fields. Please test it in your code and update it if needed according to your objects.
Also, I suggest you not to do a "Select *" because it's not a good practice for performance. Simply check for a single field.
I dont do asp.net so this is a learning curve for me and a little stuck with something that i know should be easy if you know how so apologies in advance:
Below is the C#:
rptListingAllMandatoryCourses.DataSource = listingAllMandatoryCourses();
rptListingAllMandatoryCourses.DataBind();
public DataSet listingAllMandatoryCourses()
{
DataSet dataSet = new DataSet();
User user = (User)Context.Items["CurrentUser"];
SqlConnection selectConnection = new SqlConnection(ConfigurationSettings.AppSettings["DBConnectStr"]);
SqlDataAdapter adapter = new SqlDataAdapter("dbo.procCataloguesGetAllCoursesByCategory", selectConnection);
adapter.SelectCommand.CommandType = CommandType.StoredProcedure;
// get results
adapter.SelectCommand.Parameters.Add("#FilterByDomain", SqlDbType.Bit).Value = 0;
if (user.Domain.Guid != Guid.Empty)
{
adapter.SelectCommand.Parameters.Add("#DomainID", SqlDbType.UniqueIdentifier).Value = user.Domain.Guid;
}
adapter.SelectCommand.Parameters.Add("#Limit", SqlDbType.Int).Value = 5;
adapter.SelectCommand.Parameters.Add("#FilterByDomain", SqlDbType.Bit).Value = 0;
adapter.SelectCommand.Parameters.Add("#Culture", SqlDbType.VarChar, 6).Value = "en-GB";
adapter.SelectCommand.Parameters.Add("#IsEnabled", SqlDbType.Bit).Value = null;
adapter.SelectCommand.Parameters.Add("#DomainAdminID", SqlDbType.UniqueIdentifier).Value = null;
adapter.SelectCommand.Parameters.Add("#Category", SqlDbType.UniqueIdentifier).Value = "Carousel";
adapter.SelectCommand.Parameters.Add("#UserID", SqlDbType.UniqueIdentifier).Value = null;
try
{
dataSet = new DataSet();
adapter.Fill(dataSet);
}
catch (Exception exception)
{
dataSet.Dispose();
dataSet = null;
LMS_DB.LMS_DB.LogErrorEvent(exception.Message, AuditEntryType.CatalogueCoursesGetCourses);
}
finally
{
if (selectConnection.State == ConnectionState.Open)
{
selectConnection.Close();
}
}
return dataSet;
}
protected void rptListingAllMandatoryCourses_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
DataRowView row = (DataRowView)e.Item.DataItem;
}
Frontend part:
<asp:Repeater ID="rptListingAllMandatoryCourses" runat="server" OnItemDataBound="rptListingAllMandatoryCourses_ItemDataBound">
<ItemTemplate>
<%#DataBinder.Eval(Container.DataItem, "CourseTitle")%>
</ItemTemplate>
</asp:Repeater>
Page loads fine with no errors but i cannot see any data.... ive checked the procedure and i can see data coming back for CourseTitle but does not seem to be passing to the aspx template? any ideas anyone?
screenshot with the results when i run DB query in DB
Thanks
I changed this to use ListView instead of a Repeater and worked great!