string.replace databound column in Gridview - c#

Im currently pulling a string comment from a DB into a gridview to display to the user. Throughout the string i have placed <br/>s where i want linebreaks, but am wondering how to replace the <br/>s with "Environment.Newline"s. the column is simply a boundfield.
<Columns>
<asp:BoundField HeaderText="Comment" DataField="UAComment" />
</Columns>
and im populating the table with an adapter and Fill():
adapter = new SqlDataAdapter(queryString, connection);
connection.Open();
adapter.SelectCommand = command;
recordsFound = adapter.Fill(table);
results.Text = recordsFound + " records matching query";
connection.Close();
Thanks for any info.
ps: also tried already building the string/submitting the string to the database with newlines but cant seem to get it to pull out of the db with the proper formatting.
public void Group(String message)
{
log.Append(": Group :");
log.AppendFormat(message);
log.Append("<br/>");
}
public String GetLog()
{
log.Replace("<br/>", Environment.NewLine);
return log.ToString();
}
also substituted "Environment.Newline" with #"\n", "\n", #"\r", "\r"

The easiest solution would be use a template field instead of bound field and add bind a literal in the template field with current column value. Using this it will render all the stuff in html format and the line breaks come autometically.
Example :
<asp:TemplateField>
<HeaderTemplate>
Comment
</HeaderTemplate>
<ItemTemplate>
<asp:Literal runat="server" ID="Literal1" Text='<%# Eval("UAComment") %>' />
</ItemTemplate>
</asp:TemplateField>
Hope this will fix you problem

Related

Add new data to gridview without refreshing entire gridview

I know the title might make my question look like a duplicate so please read the complete question first.
I have 3 dropdowns in my webform and based on those parameters the data is retrieved from the database and my gridview is populated. What I need is that once a result is displayed, if the user changes the parameters, the new retrieved data should be displayed below the old data. But currently my gridview is refreshing entirely and only the data based on new parameters is displayed.
I have read that one way is to use viewstate but I dont understand what it is. Can someone please help? Thank you.
Ok, so this is a difficult question. It is rather easy to filter, and have a cumulative filter.
So, say we have this screen:
And lots more rows.
So, I can say lets filter by a city.
So this:
Note how we do allow multiple city in the multi-select drop down.
So, I now have this:
Now, lets select those ONLY with a description.
So this:
And then say only active ones. So, this:
So, above is quite easy to setup. Note how any option NOT selected is left out of the critera.
but, a BIG problem exists in the above.
What happens if I want Active from say B.C. but NOT active from Alberta???
I can't do that, and hence your problem.
What we could do however is add a button to above to SAVE the resulting filter, and put the "list" of filters say into a list box or collection.
we then have a search button to search on our collection of filters.
Let me see if this can work - I'll add to above a "box" or collection of each filter.
I would think a union query with distinct row for each filter would do the trick.
So, above example is not too hard - a "cumulative" filter. In fact, the code patter for 2 or 15 filters is quite easy to do here.
However, adding up separate filter requests and combine them? That is somewhat difficult to do.
Edit: Multiple filters
so, while in above, I could say filter by city and get all active, but THEN I want to filter by another city, and get all NON active!!!
That's the problem here.
So, we would have to add code to SAVE the filter. And the HUGE problem with that is how then do we save each filter to "add up" each filter set we want?
We could try and save the raw SQL, but such SQL would be subject to sql injection, and we want to always use parameters.
So, we can and could adopt a design in which we SAVE the resulting SqlCommand object. And then merge the results.
So, now our UI becomes like this:
Lets grab and filter all those from city Edmonton, but Active,
so, this:
We now hit save filter and this:
And now we filter by say City = Banff, but don't care about active or not.
So we have this:
We then save that filter - and now we have this:
I now hit the filter button below the list of filters, and we get this:
So, how does this code work?
Well, I simple saved the Sqlcommand object to a collection (list), and thus combine the results.
So, first our markup at the top for the filter stuff.
<h4>Filters</h4>
<div style="float:left">
<asp:Label ID="Label1" runat="server" Text="Search Hotel"></asp:Label>
<br />
<asp:TextBox ID="txtHotel" runat="server"></asp:TextBox>
</div>
<div style="float:left;margin-left:20px">
<asp:Label ID="Label2" runat="server" Text="Search City"></asp:Label>
<br />
<asp:TextBox ID="txtCity" runat="server"></asp:TextBox>
</div>
<div style="float:left;margin-left:20px">
<asp:Label ID="Label3" runat="server" Text="Must Have Description"></asp:Label>
<br />
<asp:CheckBox ID="chkDescripiton" runat="server" />
</div>
<div style="float:left;margin-left:20px">
<asp:Label ID="Label4" runat="server" Text="Show only Active Hotels"></asp:Label>
<br />
<asp:CheckBox ID="chkActiveOnly" runat="server" />
</div>
<div style="float:left;margin-left:20px">
<asp:Button ID="cmdSearch" runat="server" Text="Search" CssClass="btn" OnClick="cmdSearch_Click"/>
</div>
<div style="float:left;margin-left:20px">
<asp:Button ID="cmdClear" runat="server" Text="Clear Fitler" CssClass="btn" OnClick="cmdClear_Click"/>
</div>
<div style="float:left;margin-left:20px">
<asp:Button ID="cmdTest" runat="server" Text="Save Filter"
CssClass="btn" OnClick="cmdTest_Click"
OnClientClick="return myfilterprompt()"
/>
<asp:HiddenField ID="HFilterName" runat="server" ClientIDMode="Static"/>
<script>
function myfilterprompt() {
sFilter = ""
sFilter = prompt('Enter name for filter ')
if ( (sFilter === null) || (sFilter === "") ){
return false
}
$('#HFilterName').val(sFilter)
return true
}
</script>
</div>
<div style="float:left;margin-left:30px;width:190px">
<asp:ListBox ID="lstFilters" runat="server" Width="100%" Height="100px"
DataTextField="sFilterName" >
</asp:ListBox>
<asp:Button ID="cmdMultiFilter" runat="server" Text="Filter"
CssClass="btn" OnClick="cmdMultiFilter_Click" style="float:left" />
<asp:Button ID="cmdMultiClear" runat="server" Text="Clear"
CssClass="btn" OnClick="cmdMultiClear_Click" style="float:right"/>
</div>
then below above is our grid:
<asp:GridView ID="GridView1" runat="server"
AutoGenerateColumns="False" DataKeyNames="ID"
CssClass="table" Width="60%" ShowHeaderWhenEmpty="true">
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" />
<asp:BoundField DataField="City" HeaderText="City" />
<asp:BoundField DataField="Province" HeaderText="Province" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:BoundField DataField="Active" HeaderText="Active" />
</Columns>
</asp:GridView>
So, code to load:
List<MyFilter> MyFilters = new List<MyFilter>();
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack == false)
{
SqlCommand cmdSQL = new
SqlCommand("SELECT * FROM tblHotels WHERE ID = 0");
LoadGrid(cmdSQL);
Session["MyFilters"] = MyFilters;
}
else
MyFilters = (List<MyFilter>)Session["MyFilters"];
}
public void LoadGrid(SqlCommand cmdSQL)
{
DataTable rstData = MyRstP(cmdSQL);
GridView1.DataSource = rstData;
GridView1.DataBind();
}
And now our search button:
protected void cmdSearch_Click(object sender, EventArgs e)
{
SqlCommand cmdSQL = GetMyCommand();
LoadGrid(cmdSQL);
}
SqlCommand GetMyCommand()
{
string strSQL = "SELECT * FROM tblHotels ";
string strORDER = " ORDER BY HotelName";
string strFilter = "";
SqlCommand cmdSQL = new SqlCommand();
if (txtHotel.Text != "")
{
strFilter = "(HotelName like #HotelName + '%')";
cmdSQL.Parameters.Add("#HotelName", SqlDbType.NVarChar).Value = txtHotel.Text;
}
if (txtCity.Text != "")
{
if (strFilter != "") strFilter += " AND ";
strFilter += "(City Like #City + '%') ";
cmdSQL.Parameters.Add("#City", SqlDbType.NVarChar).Value = txtCity.Text;
}
if (chkActiveOnly.Checked)
{
if (strFilter != "") strFilter += " AND ";
strFilter += "(Active = 1)";
}
if (chkDescripiton.Checked)
{
if (strFilter != "") strFilter += " AND ";
strFilter += "(Description is not null)";
}
if (strFilter != "") strSQL += " WHERE " + strFilter;
strSQL += strORDER;
cmdSQL.CommandText = strSQL;
return cmdSQL;
}
And now our save the filter button code:
protected void cmdTest_Click(object sender, EventArgs e)
{
MyFilter OneFilter = new MyFilter();
OneFilter.sFilterName = HFilterName.Value;
OneFilter.cmdSQL = GetMyCommand();
MyFilters.Add(OneFilter);
lstFilters.DataSource = MyFilters;
lstFilters.DataBind();
}
public class MyFilter
{
public string sFilterName { get; set; }
public SqlCommand cmdSQL = new SqlCommand();
}
And our multi-filter code button.
Now, for large data sets - not a great idea, but a start:
protected void cmdMultiFilter_Click(object sender, EventArgs e)
{
List<DataTable> MyTables = new List<DataTable>();
foreach (MyFilter OneFilter in MyFilters)
{
DataTable rstDT = MyRstP(OneFilter.cmdSQL);
MyTables.Add(rstDT);
}
DataTable rstData = MyTables[0];
for (int i = 1;i < MyTables.Count;i++)
{
rstData.Merge(MyTables[i]);
}
GridView1.DataSource = rstData;
GridView1.DataBind();
}
so, you can build list up of "filters" and display them in a listbox and then have a filter button that merges all of the filtering.
And one more helper routine I used:
public DataTable MyRstP(SqlCommand cmdSQL)
{
DataTable rstData = new DataTable();
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (cmdSQL)
{
cmdSQL.Connection = conn;
conn.Open();
rstData.Load(cmdSQL.ExecuteReader());
}
}
return rstData;
}
These systems can be really nice. Often a group of managers will say, lets grab all customers from west coast. Yuk - too many. Ok, only those with purchases in last 2 months - ah, that's nice.
then they say, lets get all customers who never purchased anything, but from the south - and add those to the list - but only active on our mailing list.
So, this type of slice and dice - get some of those, and then get some of these, and then combine them?
This type of business query system and being able to combine these, and those, and them, and then toss in a few more? Often they will keep going say until such time they get say 10,000 results (which happens to be how many catalogs they have left they would like to send out).
So, I solved my problem by using a little outside the box thinking. I am posting it here for anyone visiting this question or having a same problem in the future could see this:
So what I did is that I extracted the data from the database based on the parameters selected by the user from the dropdowns. In the database, I had created a temp table to store the extracted temporarily. So I inserted the data into that temporary table and used that table to populate the gridview. I had to add a reset button, when the user clicked it the all the data is deleted from the temp table and also the page reset to its default with gridview not visible and dropdowns having no selection.

Can't set value for a literal control within a GridView Row

I'm trying to set the value of a literal control populating it from an API that queries records according to a determined value in each GridView row.
So far, I'm having success retrieving the API's query string, but I can't seem to be able to populate the literal's text.
This is the GridView:
<asp:GridView
ID="gvTecnicosP4"
runat="server"
DataKeyNames="ID"
EmptyDataText="<span class='textoNaranjaSm'><i class='fa fa-bell fa-fw'></i> No tienes ningĂșn caso registrado.</span>"
AutoGenerateColumns="False" Width="100%">
<AlternatingRowStyle BackColor="#F1F1F1" />
<Columns>
<asp:TemplateField HeaderText="<i class='fas fa-user fa-fw'></i>">
<ItemTemplate>
<span class="textoNegroSm">
<asp:Literal ID="ltNombreFuncionario0" runat="server" Visible="true"></asp:Literal>
</span>
<br />
<span class="textoGrisXSm">
<asp:Literal ID="ltSam0" runat="server" Text='<%#Bind("SAM") %>'></asp:Literal>
</span>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="<i class='fas fa-user-cog fa-fw'></i>">
<ItemTemplate>
<span class="textoVerdeXSm">
<%#Eval("EsAdmin") %>
</span>
</ItemTemplate>
</asp:TemplateField>
</columns>
</asp:GridView>
The literal control ltSam0 Binds the data table's field that I'll use to consume the API, and this is working just fine.
In my code behind, I'm binding the GridView from a Stored Procedure:
DataTable dt1 = new DataTable();
using (SqlConnection conx1 = new SqlConnection(enchufe0))
{
using (SqlCommand cmd1 = new SqlCommand(spQuerySel1, conx1))
{
cmd1.CommandType = CommandType.StoredProcedure;
using (SqlDataAdapter sda = new SqlDataAdapter(cmd1))
{
sda.Fill(dt1);
gvTecnicosP4.DataSource = dt1;
}
}
}
gvTecnicosP4.DataBind();
Then, I start iterating each row, to retrieve the ltSam0 literal value and pass it to the API consult, and what I'm looking for, is that the result gets "injected" to the ltNombreFuncionario0 literal:
foreach (GridViewRow fila in gvTecnicosP4.Rows)
{
Literal ltNombreFuncionario0 = (Literal)fila.FindControl("ltNombreFuncionario0");
Literal sam = (Literal)fila.FindControl("ltSam0");
string samQry = sam.Text;
#region MS AD API Query
//all the API operations, token, JSon, etc.. (I'm consuming Microsoft's Azure Active Directory API)
#endregion
using (StreamReader reader = new StreamReader(stream))
{
Stream webResponse = responseHttpWeb.GetResponseStream();
string lector = reader.ReadToEnd();
apiquest mQuery = JsonConvert.DeserializeObject<apiquest>(lector);
if (mQuery.value.Length == 0)
{
displayNamePrintAD = "Error en AD";
}
else
{
foreach (var item in mQuery.value)
{
displayNamePrintAD = item.displayName;
}
}
}
// When debugging these lines work fine, and the literal gets populated, but in the web app view, the literal gets empty, and no value is being printed.
ltNombreFuncionario0.Text = displayNamePrintAD;
}
gvTecnicosP4.DataBind();
So the API consults works, the ltSam0 literal is being retrieved, the ltNombreFuncionario0 Literal's text is being filled, but it's not passing to the view or being rendered.

How to show fixed amount of rows in asp.net gridview

So here I have few gridviews in a row in asp.net. The problem now is it is inconsistent where some gridview would have 5 data and some would have 10. It looks ugly and since I needed to print. It's crucial.
I wanted to show max 15 rows. It is databound from the database which the user would fill up the subjects taken form(up to 15 rows). And if any of the rows doesn't have any of the data. It would leave it blank instead(note that the database didn't fills up to 15 rows.. only what is entered by the user). I've done some research but only found a few that might be related but using javascipt/changing current SQL given. I'm not allowed to use any javascript in the site (supports later would be a problem). And since I'm an intern. The sql code is given to me. I just need to implement it. What can I do to show fixed amount of rows in gridview? Is there any attribute that I can use in gridview to fill up the empty space to 15 rows?
aspx file
<asp:GridView ID="GridViewResult" runat="server" AutoGenerateColumns="False" EmptyDataText="NO RECORD" Font-Size="Small"
GridLines="Both" CellPadding="1" Height="101px" Width="100%" ShowFooter="True">
<Columns>
<asp:TemplateField HeaderText="Subjects">
<ItemTemplate>
<asp:Label ID="lbl" runat="server" Text='<%# Eval("Subjects") %>'></asp:Label>
</ItemTemplate>
<ItemStyle HorizontalAlign="Center" Width="25px" />
</asp:TemplateField>
<asp:TemplateField HeaderText="Grade">
<ItemTemplate>
<asp:Label ID="lbl1" runat="server" Text='<%# Eval("Grade") %>'></asp:Label>
</ItemTemplate>
<ItemStyle HorizontalAlign="Center" Width="25px" />
</asp:TemplateField>
</Columns>
<HeaderStyle Font-Bold="True" HorizontalAlign="Center" Height="40px"/>
<PagerStyle ForeColor="#8C4510" HorizontalAlign="Center" />
<FooterStyle HorizontalAlign="Center" />
</asp:GridView>
And the back code
Protected void LoadgvResult1()
{
SqlCommand cmdgvKep1 = new SqlCommand();
cmdgvKep1.Connection = conn;
cmdgvKep1.CommandType = CommandType.Text;
cmdgvKep1.CommandText = " SELECT ROW_NUMBER() OVER(ORDER BY Grade ASC) AS Numb, Subjects, Grade ";
cmdgvKep1.CommandText += " FROM Result_SMU ";
cmdgvKep1.CommandText += " WHERE siri = '" + siri + "' ";
conn.Open();
SqlDataAdapter adaptergvKep1 = new SqlDataAdapter(cmdgvKep1);
DataSet dsgvKep1 = new DataSet();
adaptergvKep1.Fill(dsgvKep1, "Result_SMU");
GridViewResult1.DataSource = dsgvKep1;
GridViewResult1.DataBind();
conn.Close();
}
There was a lot of problems with your code.
1)Your data access layer should not be on the same place when you are
DataBind the Grid
2)You should not use global SqlConnection. Connection pool is your
friend. Also if exception occurs your connection will never be closed.
3)Your query should use sql parameters to prevent from Sql Injection.
4) You should wrap SqlDataAdapter in using statement, so it will be disposed
after Fill.
If I understood you correctly you want to fill the grid with dummy records for some reason in the C# when the number of the records are under 15, you can add dummy rows to the fetch dataset like this.
int countRows = dsgvKep1 .Tables[0].Rows.Count;
int dummyRecords = 0;
if(countRows < 15)
{
dummyRecords = 15 - countRows;
}
for (int i = 0; i < dummyRecords; i++)
{
DataTable tbl = dsgvKep1.Tables[0];
DataRow row = tbl.NewRow();
//add dummy values if you want
//row["ColumnName"] = value;
tbl.Rows.Add(row);
}
I advise you to fix the 4 pointers which I gave you. From what I see you are intern and this will be good for you in long term.
I wrote how to create a simple data access layer in this question: checking user name or user email already exists , here you can see data layer, disposing sqlDataAdapter, preventing of not close sql connection when exception occur and also preventing sql injection using SqlComand.Parameters.

How to create a link text in a table using c#

I want to create a table format with two columns where each row will have a ProductTitle and its corresponding URL.
I am using the following code which gives the info in table format. I displays entire anchor tag in second column.
But i want only the Text to be displayed as link in second column. On click of which it should open the URL page.
DataTable dt = new DataTable();
dt.Columns.Add("ProductTitle");
dt.Columns.Add("Link");
DataRow dr = dt.NewRow();
dr["ProductTitle"] = "GOOGLE";
dr["Link"] = "<" + "a href=\"" + "http://www.google.com" + "\">Google" + "</a>";
dt.Rows.Add(dr);
Gridview1.DataSource = dt;
Gridview1.DataBind();
Could anyone suggest.
You could modify the .aspx file as follows:
...
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false">
<Columns>
<asp:BoundField DataField="ProductTitle" HeaderText="Product Title" />
<asp:BoundField DataField="Link" HtmlEncode="false" HeaderText="Link" />
</Columns>
</asp:GridView>
...
So, you should disable the automatic column generation by setting AutoGenerateColumns="false" and format the Columns section of the GridView. Please note the key element here for the link rendering, which is the HtmlEncode="false" attribute. You can also set everything in the code behind file:
GridView1.AutoGenerateColumns = false;
var productTitleField=new BoundField();
productTitleField.DataField="ProductTitle";
productTitleField.HeaderText="Product Title";
var linkField=new BoundField();
linkField.DataField="Link";
linkField.HeaderText="Link";
linkField.HtmlEncode=false;
GridView1.Columns.Add(productTitleField);
GridView1.Columns.Add(linkField);
Try this
dr["Link"] = "<a href='http://www.google.com'>Google</a>";
I tried
Label1.Text = "<a href='http://www.google.com'>Google</a>";
It works.
Second try :
We cannot save any thing else other than .NET types like string,int .etc ,so try asp:HyperLink like this
<ItemTemplate>
<asp:HyperLink ID="HyperLink1" runat="server" Text='<%# Eval("ProductTitle")%>' NavigateUrl='<%# Eval("Link") %>'></asp:HyperLink>
</ItemTemplate>
and
dr["ProductTitle"] = "Goole";
dr["Link"] = "http://www.google.com";
There is actually a specific column designed just for what you want to do, it's the HyperLinkField column.
<asp:HyperLinkField
HeaderText="Header"
DataTextField="LinkText"
DataNavigateUrlFields="LinkURL"
DataNavigateUrlFormatString="http://google.com/q={0}" />
You can then ensure that your data source has the appropriate columns for the link text and navigate url fields.
You can configure it if you have a fixed text or fixed url to use the Text or NavigateURL properties instead of the Data... counterparts, and you can use or not use format strings as needed.

Get values from DataTable without data binding to UI controls?

I always get values from the database directly to a control like this:
Code-behind:
DataTable table = GetUserInfo();
UserInfo.DataSource = table;
UserInfo.DataBind();
string FirstName = lblFirstName.Text;
string LastName = lblLastName.Text;
DateTime BecomeAMember = DateTime.Parse(lblBecomeAMember.Text);
Markup:
<asp:Label ID="lblCity" runat="server" Text='<%# Eval("FirstName") %>' />
<asp:Label ID="lblLastName" runat="server" Text='<%# Eval("LastName") %>' />
<asp:Label ID="lblBecomeAMember" runat="server" Text='<%# Eval("BecomeAMember", "{0:dd MMM yyy) %>' />
There has to be a way to use the data in code-behind without putting it to a label and then use String text = label.Text;
I need the minutes and hours from BecomeAMember, and I don't want to use another Label with the full DateTime and make it invisible. It would be nice to know how to get the other values as well.
You may use DataTable methods to read values directly from the table object.
For instance,
string firstName = table.Rows[0]["FirstName"].ToString();
or
foreach (DataRow row in table.Rows)
{
//
}
Or use Select() method to search on specified field.
DataRow[] rows = table.Select("column1='value1'");
Yes, you can directly investigate the data held in the DataTable.
DataTable can be made into an IEnumerable, and can be queried. In your case:
var datetimes = table.AsEnumerable().Select(x => x.Field<DateTime>("BecomeAMember"));
If you really only expect a single row, you can do either:
var dt = table.AsEnumerable().Select(x => x.Field<DateTime>("BecomeAMember")).Single();
or:
var dt = (DateTime) table.Rows[0]["BecomeAMember"];
Then format dt using ToString with a format string.

Categories