Recent problems I've had are making me question my whole philosophy and assumptions regarding GridViews.
Currently, I have used something along the lines of the following model.
In Markup:
<asp:UpdatePanel ID="pnlSearch" UpdateMode="Conditional" runat="server">
<ContentTemplate>
<asp:TextBox ID="txtSearch" runat="server"
ontextchanged="txtSearch_TextChanged"></asp:TextBox>
</ContentTemplate>
</asp:UpdatePanel>
<asp:UpdatePanel ID="pnlGridView" UpdateMode="Conditional" runat="server">
<ContentTemplate>
<asp:GridView ID="GridView1" EnableViewState="false" AllowPaging="true" PageSize="20" DataSourceID="MyDataSource" runat="server" AutoGenerateColumns="False">
<Columns>
<asp:BoundField DataField="COL_1" HeaderText="Happy Data" SortExpression="COL_1" />
<asp:BoundField DataField="COL_2" HeaderText="Happy Related Data" SortExpression="COL_2" DataFormatString="{0:M/dd/yyyy}" />
</Columns>
</asp:GridView>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="txtSearch" EventName="TextChanged" />
</Triggers>
</asp:UpdatePanel>
<asp:SqlDataSource ID="MyDataSource" runat="server"></asp:SqlDataSource>
Pretty basic stuff. A GridView. A data source. A text box for searching results. I include the UpdatePanels only because I'm somewhat convinced they could be part of my problems.
Over in my code behind, I usually would do something like this:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
MyDataSource.ConnectionString = ConfigurationManager.ConnectionStrings["OracleConnectionString"].ConnectionString;
MyDataSource.ProviderName = ConfigurationManager.ConnectionStrings["OracleConnectionString"].ProviderName;
GridView1.EmptyDataText = "No comments found.";
PopulateGridView();
}
}
protected void PopulateGridView()
{
string strQuery = #"SELECT COL_1,
COL_2
FROM some_table
WHERE COL_3 = :important_filter";
MyDataSource.SelectCommand = strQuery;
MyDataSource.SelectParameters.Clear();
MyDataSource.SelectParameters.Add(":important_filter", Request.QueryString["filter"]);
GridView1.DataBind();
GridView1.PageIndex = 0;
}
protected void txtSearch_TextChanged(object sender, EventArgs e)
{
string strQuery = #"SELECT COL_1,
COL_2
FROM some_table
WHERE COL_3 = :important_filter AND lower(COL_2) LIKE :search";
MyDataSource.SelectCommand = strQuery;
MyDataSource.SelectParameters.Clear();
MyDataSource.SelectParameters.Add(":important_filter", Request.QueryString["filter"]);
MyDataSource.SelectParameters.Add(":search", "%" + txtSearch.Text.Trim().ToLower() + "%");
GridView1.DataBind();
GridView1.PageIndex = 0;
}
Nothing too fancy. I initially connect up the data source to a connection string from the config file (as is necessary in a multi instance environment), wire up the query and databind. On searches, I change the query and rebind.
The only problem?
The above doesn't work. Why? The data source loses it's query, connection string, provider name, etc on post back. So the gridview commits suicide. The same thing happens when I try to change pages...either on initial load or with a search populated.
I "solved" this problem last week by manually adding the datasource to control state and repopulating the values from control state, but that seems hackish.
What am I not understanding?
You have the update mode set to conditional so you need to call update on 'pnlGridView'
GridView1.DataBind();
GridView1.PageIndex = 0;
pnlGridView.Update();
I would also revist how you are using your DataSource
<asp:SqlDataSource ID="ProductsDataSource" runat="server"
ConnectionString="<%$ ConnectionStrings:OracleConnectionString %>"
SelectCommand="SELECT COL_1, COL_2 FROM some_table WHERE COL_3 = #important_filter">
<SelectParameters>
<asp:ControlParameter ControlID="textBox?not sure where this is coming from" PropertyName="SelectedValue" Name="important_filter" Type="string" DefaultValue="" />
</SelectParameters>
</asp:SqlDataSource>
You could also use a server side event handler and set the important filter manually.
protected void SQLDataSource_Selecting(object sender, SQLDataSourceSelectingEventArgs e) {
e.InputParameters["important_filter"] = "whatever";
}
And add the event to your markup for your SQLDataSource.
<asp:SqlDataSource ID="MyDataSource" runat="server" OnSelecting="SQLDataSource_Selecting" />
Related
I have just a simple message page which consists of From: Text: and a Submit button, then I have another page, which contains nothing, it's my "Message Board" the most recent posted message goes on top of the board, both are aspx pages with master page.
I have a SQL DB, I'm already assuming there will be a table with From: Message:(with varchar i think), but what i don't understand how it will get inserted into the messageboard page in a most recent to oldest list fashion.
Message.aspx - From: Text: Submit
MessageBoard.aspx - just a div , messages submitted will appear here in a drop down list
I want it to be super simple no cool features, only "Submit the message" -> "Appears on MessageBoard.aspx to everyone",
and that's it
Ok, there are seveal moving parts.
Assuming you have SQL server running. Assuming you have a valid conneciton?
Ok, then on the post a new message page, you have this markup:
<h3>Post a message</h3>
<h4>enter your name</h4>
<asp:TextBox ID="txtName" runat="server" Width="250px"></asp:TextBox>
<br />
<h4>Enter your message</h4>
<asp:TextBox ID="txtMsg" runat="server" Height="185px" Width="520px"
TextMode="MultiLine" Font-Size="Large" style="border-radius:20px;border:solid 2px"
></asp:TextBox>
<br />
<br />
<asp:Button ID="cmdNewMessage" runat="server" Text="Post Message" CssClass="btn"
OnClick="cmdNewMessage_Click" />
And code behind looks like this:
protected void Page_Load(object sender, EventArgs e)
{
}
protected void cmdNewMessage_Click(object sender, EventArgs e)
{
string strSQL =
#"INSERT INTO tblMessages (UName, Message, MessageDate)
VALUES (#UName, #Message, #MessageDate)";
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
conn.Open();
cmdSQL.Parameters.Add("#UName", SqlDbType.NVarChar).Value = txtName.Text;
cmdSQL.Parameters.Add("#Message",SqlDbType.NVarChar).Value = txtMsg.Text;
cmdSQL.Parameters.Add("#MessageDate", SqlDbType.NVarChar).Value = DateTime.Now;
cmdSQL.ExecuteNonQuery();
}
}
Response.Redirect("MessageBoard.aspx");
}
So, it looks like this:
when you hit post message, we jump to this page, and markup:
<asp:Button ID="cmdPost" runat="server"
Text="Post a new message"
CssClass="btn" OnClick="cmdPost_Click" />
<br />
<br />
<h2>Messages</h2>
<asp:GridView ID="GridView1" runat="server" Width="50%"
AutoGenerateColumns="False" DataKeyNames="ID" >
<Columns>
<asp:BoundField DataField="UName" HeaderText="Posted by" />
<asp:BoundField DataField="MessageDate" HeaderText="At" ItemStyle-Width="180px" />
<asp:TemplateField HeaderText="Message" >
<ItemTemplate>
<asp:Textbox ID="txtMsg" runat="server" TextMode="MultiLine" Width="100%"
Text='<%# Eval("Message") %>'
Height='<%# (Regex.Matches(Eval("Message").ToString() , System.Environment.NewLine).Count + 1) * 30 %>'
>
</asp:Textbox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
And code is:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadGrid();
}
void LoadGrid()
{
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
string strSQL = "SELECT * FROM tblMessages ORDER BY MessageDate DESC";
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
conn.Open();
GridView1.DataSource = cmdSQL.ExecuteReader();
GridView1.DataBind();
}
}
}
protected void cmdPost_Click(object sender, EventArgs e)
{
Response.Redirect("NewMessage.aspx");
}
And we now see/have this:
You don't explain what you mean by "what i don't understand how it will get inserted into the messageboard page in a most recent to oldest list fashion", so I can only guess.
When a new message is posted, you insert it into the database, including a DateTime column. Your message list page then just grabs the latest nn messages, ordered by newest first.
I'm assuming that you know how to do that. If not, do some reading about Entity Framework Core, as that provides a very good way of handling databases.
So, in princple, your question is no more complex than that. However, there are many variations on this, such as having the message list updated in real time, for which you should use SignalR, but without more specific explanation of what you want, it's hard to make any suggestions.
I'm displaying a datatable that selects a number of elements from the database (IncomingsId, Type, Cost, Frequency) and I'm not sure how to delete a row when a button is clicked.
I've tried many solutions so far but nothing is working.
Here is the button I have within my Grid view
<asp:TemplateField HeaderText="Delete">
<ItemTemplate>
<asp:button id="DeleteRowButton" text="Delete Record" onclick="DeleteRowButton_Click" runat="server"/>
</ItemTemplate>
</asp:TemplateField>
And here is the code behind this page were I am creating the datatable.
SqlConnection con;
public _Default()
{
con = new SqlConnection(#"MySQLConnection");
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
DisplayRecord();
}
}
public DataTable DisplayRecord()
{
string userId = (HttpContext.Current.User.Identity.GetUserId());
SqlDataAdapter Adp = new SqlDataAdapter("select * from Incomings where AspNetUsersId = '" + userId +"'", con);
DataTable Dt = new DataTable();
Dt.AcceptChanges();
Adp.Fill(Dt);
grid1.DataSource = Dt;
grid1.DataBind();
return Dt;
}
public void DeleteRowButton_Click(object sender, EventArgs e)
{
}
Cheers in advance for any help. I'm sure it's a simple resolution
You need a way for your code to know which ID to delete. Here is how I would normally do it:
Replace your button with an ItemTemplate, and add the button in here instead:
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:Button Text="Delete" runat="server" CommandArgument='<%# Eval("userId") %>' CommandName="Delete" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
When you have the button this way, you now have access to a CommandArgument and CommandName attributes. Notice the argument I am passing is Eval("userId"), the command name (as you will see later) is used to recognize what action you want to execute (this could be anything, is just a name).
Replace the CommandArgument with whatever value(s) you want to pass to the server, using the name that came from the database/datasource (I am guessing it would be userId).
Then, to capture this you need to implement the RowCommand event of the GridView, and intercept the correct CommandName:
public void GridView1_RowCommand(Object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Delete")
{
string userId = e.CommandArgument.ToString();
//do something with the id
}
}
Here you have to make sure the CommandName in your button, matches to whatever action you want to execute in the RowCommand. This should do the trick.
Don't forget to bind the event to your GridView:
<asp:GridView OnRowCommand="GridView1_RowCommand" ID="GridView1" runat="server">
...
</asp:GridView>
just use this for the front-end code
<asp:GridView ID="grid1" OnRowDeleting="OnRowDeleting" DataKeyNames="deleteR" runat="server" AutoGenerateColumns="False" CellPadding="4" GridLines="None" style="width:100%" >
<columns>
<asp:TemplateField HeaderText="Delete Row">
<ItemTemplate>
<asp:Button ID="btnDelete" runat="server" class="btn btn-primary" Text="Delete" CommandName="Delete" OnRowDataBound="OnRowDataBound" />
</ItemTemplate>
</asp:TemplateField>
And have this in behind it:
protected void OnRowDeleting(object sender, GridViewDeleteEventArgs e)
{
int deleteR= Convert.ToInt32(grid1.DataKeys[e.RowIndex].Values[0]);
//have a sql statement here that add's the parameter ID for the row you want to delete, something like
SqlCommand com = new SqlCommand ("Delete FROM yourdatabase Where yourID = #yourID"
com.Parameters.AddWithValue("#yourID", yourID)
}
What you're looking for is indeed a simple solution.
You can use a foreach loop to search all DataRows within the DataTable for some kind of ID.Here's an example of what I mean:
String s = "/* IncomingsId for what you want to delete */";
foreach (DataRow r in dt.Rows) {
if (r["IncomingsId"].ToString().Equals(s)) {
dt.Rows.Remove(r);
}
}
Just a quick update for anyone that's helped me, thanks for your advice.
Asp.Net has it's own built in AutoGenerateDeleteButton and I set that to true and ran a bit of code behind it.
A simple solution that really shouldn't have taken me all day to complete!
I'm having trouble displaying a DataList in a aspx page.
protected void btnAdminExecuteQuery_Click(object sender, EventArgs e)
{
SqlDataAdapter _SqlDA;
try
{
_SqlConnection.Open();
_SqlCommand = new SqlCommand(txtBoxAdminQuery.Text, _SqlConnection);
_SqlDA = new SqlDataAdapter(_SqlCommand);
DataSet _SqlDS = new DataSet();
_SqlDA.Fill(_SqlDS);
_SqlConnection.Close();
DL.DataSource = _SqlDS.Tables[0];
DL.DataBind();
}
catch (Exception ex)
{
if (this._SqlConnection.State == ConnectionState.Open)
{
this._SqlConnection.Close();
}
txtBoxAdminErrorMsg.Text = ex.Message;
}
}
I'm sure the ConnectionString and command are correct because I've tested them, and I can see in the debugger that the DataList has rows, it has Data but it's just not displaying.
This is what I see when I execute the query on the 'Admin Panel'
HTML:
<asp:TextBox ID="txtBoxAdminQuery" runat="server" TextMode="MultiLine"></asp:TextBox>
<asp:Button ID="btnAdminExecuteQuery" runat="server" OnClick="btnAdminExecuteQuery_Click" Text="Execute Query" />
<asp:TextBox ID="txtBoxAdminErrorMsg" runat="server" Enabled="False" Height="68px" ReadOnly="True" TextMode="MultiLine" Width="463px"></asp:TextBox>
<asp:SqlDataSource ID="_SqlDS" runat="server" ConnectionString="<%$ ConnectionStrings:CompanyConnectionString %>" SelectCommand="SELECT * FROM [Accounts]"></asp:SqlDataSource>
<asp:DataList ID="DL" runat="server" CellPadding="1" CellSpacing="1" RepeatColumns="2">
</asp:DataList>
</div>
</form>
My goal is to run custom queries and display the results in the DataList, I know how to configure the DataList through Visual Studio Designer, but if I do it from there the Query is static I can't change it, as far as I know.
Proving that the _SqlDS has data:
I want to pass the sql select query from the code behind and based on that query, data should be automatically fill in the grid view. The select query will be different i.e. it can select any tables or views. My code is as follows.
CodeBehind
Protected void ExecuteButton_Click(object sender, EventArgs e)
{
string sql = SqlQueryTextBox.Text;
SqlDataSource1.SelectCommand = sql;
GridView1.Databind();
}
Asp Markup
<asp:GridView ID="GridView1" runat="server"
DataSourceID="SqlDataSource1" AutoGenerateColumns="true">
</asp:GridView>
But nothing is loaded in grid view. Upto now I have used grid view only to bind single table and its columns. Is there any mistake in my logic? How can I fill the grid with dynamic data?
This works fine for me...
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="Data Source=*******Initial Catalog=*******;Persist Security Info=True;User ID=*******;Password=*******" ></asp:SqlDataSource>
<div>
<asp:TextBox ID="SqlQueryTextBox" runat="server" ></asp:TextBox>
<asp:Button ID="ExecuteButton" OnClick="ExecuteButton_Click" runat="server" Text="Execute"/>
</div>
<div>
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" AutoGenerateColumns="true" />
</div>
..
protected void ExecuteButton_Click(object sender, EventArgs e)
{
SqlDataSource1.SelectCommand = SqlQueryTextBox.Text;
GridView1.DataBind();
}
Ps. I used "SELECT * FROM information_schema.tables" as my select statement
I think you need to check your connection string. and then get back to us.
string sql = SqlQry.Text;
SqlDataSource1.SelectCommand = sql;
SqlDataSource1 .Select (DataSourceSelectArguments .Empty );
Gv_1.DataBind();
I have a webapp that calls on a SQL Query for a list of applications impacted by a project. I want my admins to be able to click edit and add remove applications to this list at will. Currently when they click edit they see every single Application that is Impacted by ANY project as part of the list box even though in the Gridview they only see the Applications Impacted by that specific project. When I hard code the value for the project it works, but I need it to be a variable depending on which project my admins click on to edit.
select
Applications.ApplicationName,
Projects.ProjectName
from ImpactedApplications
inner join Applications
on ImpactedApplications.AppId=Applications.AppId
inner join Projects
on ImpactedApplications.ProjectId=Projects.ProjectId
Where Projects.ProjectId=57 <--This is Hardcoded. I need this to be dynamic.
Adding Code
<asp:TemplateField HeaderText="ImpactedApplications">
<EditItemTemplate>
<asp:ListBox ID="ListBox1" runat="server" DataSourceID="ImpactedApps"
DataTextField="ApplicationName" DataValueField="ProjectName" Width="250px"></asp:ListBox>
<asp:Button ID="Button1" runat="server" Text="Add" />
<asp:Button ID="Button2" runat="server" Text="Remove" />
<asp:ListBox ID="ListBox3" runat="server" DataSourceID="Applications"
DataTextField="ApplicationName" DataValueField="AppId" Width="250px">
</asp:ListBox>
<br />
<asp:SqlDataSource ID="ImpactedApps" runat="server"
ConnectionString="<%$ ConnectionStrings:LandscapeServicesConnectionString %>"
SelectCommand="select Applications.ApplicationName, Projects.ProjectName
from ImpactedApplications
inner join Applications
on ImpactedApplications.AppId=Applications.AppId
inner join Projects
on ImpactedApplications.ProjectId=Projects.ProjectId
where Projects.ProjectName=#Projectname">
<SelectParameters>
<asp:FormParameter DefaultValue="PO Consolidation (EDW)"
FormField="Gridview1 - Column[2] - Project Name" Name="Project Name" />
</SelectParameters>
</asp:SqlDataSource>
Adding Background Code
public partial class Update : System.Web.UI.Page
{
public string query { get; set; }
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["LandscapeServicesConnectionString"].ConnectionString);
DataSet dt = new DataSet();
protected void Page_Load(object sender, EventArgs e)
{
con.Open();
}
protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)
{
GridView1.EditIndex = e.NewEditIndex;
}
}
Create a parameterized query:
select
Applications.ApplicationName,
Projects.ProjectName
from ImpactedApplications
inner join Applications
on ImpactedApplications.AppId=Applications.AppId
inner join Projects
on ImpactedApplications.ProjectId=Projects.ProjectId
where Projects.ProjectId=#projectId
Then when you create your SqlCommand add a parameter and give it the value from your form:
cmd.Parameters.AddWithValue("#projectId",projectId);