How to programmatically replace an HyperLinkField in a ASP.NET GridView - asp.net

I have an ASP.NET Web Forms application. In my application I have a GridView that works smoothly. I have several text fields and the last one is a <asp:hyperlinkfield>.
Now I would like to programmatically change the field by placing a simple link instead of the hyperlinkfield if a specific condition is fulfilled. Therefore I catch the onRowDataBound event:
Sub myGridView_RowDataBound(ByVal sender As Object, ByVal e As GridViewRowEventArgs) Handles myGridView.RowDataBound
If (condition) Then
Dim link = New HyperLink()
link.Text = "login"
link.NavigateUrl = "login.aspx"
e.Row.Cells(3).Controls.Add(link)
End If
End If
End Sub
where n is the cell where the hyperlinkfield is placed. With this code it just adds to the hyperlinkfield the new link. How can I replace it?
PS: The code is in VB6 but I am a C# programmer, answers with both languages are accepted

Remove the control you want to replace from the collection before adding the new one:
protected void TestGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
HyperLink newHyperLink = new HyperLink();
newHyperLink.Text = "New";
e.Row.Cells[3].Controls.RemoveAt(0);
e.Row.Cells[3].Controls.Add(newHyperLink);
}
}
But I agree with the others, just change the existing link's properties:
protected void TestGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
HyperLink link = e.Row.Cells[0].Controls[0] as HyperLink;
if (link != null)
{
link.Text = "New";
link.NavigateUrl = "New";
}
}
}

In situations like that I typically convert the bound field to a templated field.
<asp:TemplateField HeaderText="Title" SortExpression="Title">
<ItemTemplate>
<asp:HyperLink ID="TitleHyperLink" runat="server" ></asp:HyperLink>
</ItemTemplate>
</asp:TemplateField>
And do the rest of the work in the codebehind.
protected void grid_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
var link = (HyperLink)e.Row.FindControl("TitleHyperLink");
if (link != null)
{
if (condition)
{
link.Text = "login";
link.NavigateUrl = "login.aspx";
}
else
{
link.Text = "default text";
link.NavigateUrl = "default.aspx";
}
}
}
}

Instead of creating a new link at this point, grab the link that's already generated as part of the field.
If (e.Row.RowType = DataControlRowType.DataRow) Then
Dim link = e.Row.Cells(3).Controls(0)
link.Text = "login"
link.NavigateUrl = "login.aspx"
End If
EDIT: Added If block to avoid action outside item rows.

You could do this in your aspx file :
<asp:HyperLink Text='<%# condition ? "TextIfTrue" : "TextIfFalse" %>' NavigateUrl='<%# condition ? "UrlIfTrue" : "UrlIfFalse" %>' />
or cast your
e.Row.Cells(3).Controls(0)
into a hyperlink and change its values.

You can use in the aspx:
<asp:HyperLink ID="HyperLink1" CssClass="exercise" runat="server" NavigateUrl="#">Search ¡here!</asp:HyperLink>
In the codebehind:
You can use also a method:
public string SharePoint(string x)
{
string page1, page2;
if (x== "1")
{
string page1="http://nwpage/files.zip";
return page1;
}
else
{
string page2="http://example2.aspx";
return page2;
}
}
If I call the control in the other method or page load, you can add HyperLink1 with the path
string path= SharePoint(x);
HyperLink1.NavigateUrl = path;

Related

asp.net set command argument

I am using OnRowDataBound to automatically add a link button to my grid view that looks like this. The problem I am having is setting the command argument.
<asp:LinkButton ID = "lnkDelete" Text = "Delete" CommandArgument = '<%# Eval("Value") %>' runat = "server" OnClick = "DeleteFile" />
Below is the code that adds the links. I set the command argument to Eval("Value") but that doesn't work. Here is a link to the original code that I'm trying to change so it is dynamic.
protected void OnRowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
LinkButton lnkView = new LinkButton();
lnkView.ID = "lnkDelete";
lnkView.Text = "Delete";
lnkView.Click += DeleteFile;
lnkView.CommandArgument = Eval("Value");
e.Row.Cells[1].Controls.Add(lnkView);
}
RowDataBound is not the right event to add controls dynamically because they need to be re-created on every consecutive postback. RowDataBound is triggered only if you call GridView.DataBind().
So use RowCreated instead, but assign the CommandArgument value in RowDataBound and don't use Eval("Value") but the actual datasource which you get from e.Row.DataItem.
Something like this should work:
protected void OnRowCreated(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
LinkButton lnkView = new LinkButton();
lnkView.ID = "lnkDelete";
lnkView.Text = "Delete";
lnkView.Click += DeleteFile;
e.Row.Cells[1].Controls.Add(lnkView);
}
}
protected void OnRowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
LinkButton lnkView = (LinkButton)e.Row.FindControl("lnkDelete");
var rowView = (DataRowView)e.Row.DataItem;
lnkView.CommandArgument = rowView.Row.Field<string>("Value");
}
}
If this throws an exception at runtime you need to change (DataRowView)e.Row.DataItem to the actual datasource which you can get from the debugger.
Edit: as commented it is a ListItem and you want to use it's Value property:
var item = (ListItem) e.Row.DataItem;
lnkView.CommandArgument = item.Value;

Gridview - Databinding methods such as Eval(), XPath(), and Bind() can only be used in the context of a databound control

the problem comes from:
double dItemPremium = (Eval("Premium")!= DBNull.Value) ? (double)(Eval("Premium")) : 0;
and I need help changing it.
I am working with a Gridview.
protected void dgCustomer_DataBound(object sender, System.EventArgs e)
{
Label pLabel = new Label();
double dItemPremium = (Eval("Premium")!= DBNull.Value) ? (double)(Eval("Premium")) : 0;
pLabel.Text = dItemPremium.ToString("0.00");
dTotal_m += dItemPremium;
dgCustomer.HeaderRow.TableSection = TableRowSection.TableHeader;
dgCustomer.FooterRow.TableSection = TableRowSection.TableFooter;
dgCustomer.FooterRow.Controls.Add(pLabel);
}
protected void dgCustomer_RowCreated(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
dTotal_m += Convert.ToDouble(DataBinder.Eval(e.Row.DataItem,"Premium"));
}
else if (e.Row.RowType == DataControlRowType.Footer)
{
e.Row.Cells[0].Text = "Totals:";
e.Row.Cells[1].Text = dTotal_m.ToString("0.00");
e.Row.Cells[1].HorizontalAlign = HorizontalAlign.Right;
e.Row.Font.Bold = true;
}
}
In HTML I used
<asp:TemplateField>
<ItemTemplate>
<%#DataBinder.Eval(DataItem,"Premium")%></ItemTemplate>
<HeaderTemplate>
Premium Amount Paid</HeaderTemplate>
</asp:TemplateField>
I added DataBinder and DataItem but still nothing.
Thank you!
You can access bound values in code behind using the controls. Eval, Bind, etc methods are to be used to bind values to controls. There are many ways to access bound values in code bebind, one of them is
e.Row.Cells[0].Text
another is putting bound value in Label and accessing it like,
string tempstr=((Label)dgCustomer.Rows[e.RowIndex].Cells[<cell_number>].FindControl("Label_ID")).Text;
In case anyone have this problem, here is another solution: on the aspx file change from <%# to <%=
<ItemTemplate>
<%= DataBinder.Eval(DataItem,"Premium")%></ItemTemplate>
<HeaderTemplate>

Wrong linkbutton command argument after sorting gridview

In an asp:TemplateField column of a GridView, I have a LinkButton that passes a command argument to a function that deletes the row when it is clicked. However, after the GridView is sorted, the LinkButton passes the wrong argument. Also, the GridView loses the sort order.
What am I doing wrong?
Here is my code:
<!---master page---->
<asp:GridView runat="server" ID="companies_grid" AllowSorting="true"
AutoGenerateColumns="false" OnSorting="companies_grid_OnSorting"
OnRowDataBound="companies_grid_OnRowDataBound" >
<Columns>
<%--Company Name--%>
<asp:TemplateField HeaderText="Company Name" SortExpression="Name">
<ItemTemplate>
<asp:LinkButton ID="LinkButton1" runat="server"
OnClick="removeCompany_click" />
<a href='<%#Eval("URL")%>'><%#Eval("Name")%></a>
</ItemTemplate>
</asp:TemplateField>
//more columns
<!---code behind---->
protected void Page_Load(object sender, EventArgs e)
{
companies = GetCompanyData();
companies_grid.DataSource = companies;
companies_grid.DataBind();
}
protected void companies_grid_OnSorting(object sender, GridViewSortEventArgs e)
{
//sort is made up of column to sort by + direction
companies.DefaultView.Sort = e.SortExpression.ToString() + " " + GetSortDirection(e.SortExpression, "companiesExpression", "companiesDirection");
companies_grid.DataSource = companies;
companies_grid.DataBind();
}
private string GetSortDirection(string column, string expressionViewState, string directionViewState)
{
// By default, set the sort direction to ascending.
string sortDirection = "ASC";
// Retrieve the last column that was sorted.
string sortExpression = ViewState[expressionViewState] as string;
if (sortExpression != null)
{
// Check if the same column is being sorted.
// Otherwise, the default value can be returned.
if (sortExpression == column)
{
string lastDirection = ViewState[directionViewState] as string;
if ((lastDirection != null) && (lastDirection == "ASC"))
{
sortDirection = "DESC";
}
}
}
// Save new values in ViewState.
ViewState[directionViewState] = sortDirection;
ViewState[expressionViewState] = column;
return sortDirection;
}
protected void companies_grid_OnRowDataBound(Object Sender, GridViewRowEventArgs e)
{
GridViewRow currRow = e.Row;
if (currRow.RowType == DataControlRowType.DataRow)
{
LinkButton deleteCompButton = (LinkButton)e.Row.FindControl("LinkButton1") as LinkButton;
deleteCompButton.CommandArgument = ((DataRowView)e.Row.DataItem)["Company_ID"].ToString();
deleteCompButton.Text = ((DataRowView)e.Row.DataItem)["Company_ID"].ToString();
}
}
protected void removeCompany_click(Object sender, EventArgs e)
{
bool removeSuccess = false;
string idToDelete = ((LinkButton)sender).CommandArgument as string;
removeSuccess = UserInfo.DeleteCompany(idToDelete);
if (removeSuccess)
{
Response.Redirect(Request.RawUrl);
}
}
Here was the issue:
When the LinkButton is clicked, the first thing that happens is the page reloads. However, Response.Redirect(Request.RawUrl) doesn’t preserve the ViewState, so the sort order is lost. Therefore, the GridView is repopulated with unsorted data.
Then, the LinkButton onClick event function is called. The Object passed in is the LinkButton from the correct row number, but since the sort order of the table had changed (back to its unsorted state), the LinkButton in that row was no longer the LinkButton the user had clicked. Therefore, the command argument was wrong.
To fix the issue:
I changed all the ViewState[string] to Session[string] (so that the sort direction is preserved when the page reloads), and added the following code in the Page_Load function, before the GridView is bound:
if (Session["companiesExpression"] != null
&& Session["companiesDirection"] != null)
{
companies.DefaultView.Sort = Session["companiesExpression"] + " " +
Session["companiesDirection"];
}

Cannot find selected value of dynamically added controls in repeater

I am creating a survey page that has a list of questions and answers that can be radiobuttonlists, checkboxlists or textboxes. These controls are added dynamically to a Repeater in its ItemDataBound event using Controls.Add.
I've managed to render the page ok but when I submit the form and iterate over the controls in the repeater to get the selectedvalues of the radiobuttons and textbox values, FindControl returns null. What do I need to do to get get the selected values? I've tried iterating over the RepeaterItems but that returned null too. I've tried different types of FindControl but it never resolves the control types.
It works if I add a declarative DataBinder in the Repeater like this
<asp:Repeater ID="rptSurvey" runat="server" Visible="true" EnableViewState="true" >
<ItemTemplate>
<%# DataBinder.Eval(Container.DataItem, "Question") %>
</ItemTemplate>
</asp:Repeater>
However, I want want to dynamically add the controls but in doing this i cant get the selectedvalues when submitting. This is tha main structure of my code...
<html>
<asp:Repeater ID="rptSurvey" runat="server" Visible="true">
</asp:Repeater>
<asp:Button ID="btnSubmit" runat="server" Text="Submit" OnClick="btnSubmit_Click" />
</html>
protected void Page_Load(object sender, EventArgs e)
{
...
if (!IsPostBack)
{
rptSurvey.DataSource = GetQuestions();
rptSurvey.DataBind();
}
...
}
protected void rptSurvey_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
string question = (DataBinder.Eval(e.Item.DataItem, "Question")).ToString();
litQuestion = new Literal();
litQuestion.Text = question;
RadioButtonList rblAnswer = (RadioButtonList)item;
rptSurvey.Controls.Add(rblAnswer);
}
}
protected void btnSubmit_Click(object sender, EventArgs e)
{
...
Dictionary<int, string> answers = new Dictionary<int, string>();
try
{
var list = FindControls(rptSurvey, c => c is RadioButtonList || c is CheckBoxList || c is TextBox);
foreach (Control item in list)
{
QuestionId = int.Parse(Questions.Rows[list.IndexOf(item)][0].ToString());
if (item is TextBox)
{
TextBox txtAnswer = (TextBox)item;
answers.Add(QuestionId, txtAnswer.Text);
}
else if (item is RadioButtonList)
{
RadioButtonList rblAnswer = (RadioButtonList)item;
answers.Add(QuestionId, rblAnswer.SelectedItem.Text);
}
else if (item is CheckBoxList)
{
// Iterate through the Items collection of the CheckBoxList
string cblMultiAnswer = "";
for (int i = 0; i < cblAnswer.Items.Count; i++)
{
if (cblAnswer.Items[i].Selected)
{
cblMultiAnswer += cblAnswer.Items[i].Value + ",";
}
}
answers.Add(QuestionId, cblMultiAnswer);
}
}
bSurvey.BLInsertSurveyAnswers(answers, dateCreated, _userEmail);
}
}
public static List<Control> FindControls(Control parent, Predicate<Control> match)
{
var list = new List<Control>();
foreach (Control ctl in parent.Controls)
{
if (match(ctl))
list.Add(ctl);
list.AddRange(FindControls(ctl, match));
}
return list;
}
you have to create the control tree first (always - not only on non-postbacks). do it in the oninit or onpreload event.
look here: https://web.archive.org/web/20211020131055/https://www.4guysfromrolla.com/articles/081402-1.aspx

How do I disable the select button text in a gridview after clicking it once? (ASP.NET)

as the title says, How do I disable the select button text in a gridview after clicking it once? I want to click it once, then have the select cell area render an image (and the image not clickable or linking to anything).
Any ideas?
protected void Page_Load(object sender, EventArgs e)
{
dn = new holdDataContext();
if (!(Page.IsPostBack))
{
// GridView1.DataSource = dn.tennis.ToList();
// GridView1.DataBind();
GridView1.DataSource = from c in dn.tennis
orderby c.ID descending
select c;
GridView1.DataBind();
}
}
protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
{
DataSet ds = null;
if (Session["oro"] == null)
{
ds = new DataSet();
DataTable dt = new DataTable();
dt.Columns.Add(new DataColumn("Name"));
dt.Columns.Add(new DataColumn("Description"));
ds.Tables.Add(dt);
Session["oro"] = ds;
}
else
{
ds = (DataSet)Session["oro"];
}
DataRow row = ds.Tables[0].NewRow();
row["Name"] = GridView1.Rows[GridView1.SelectedIndex].Cells[2].Text;
row["Description"] = GridView1.Rows[GridView1.SelectedIndex].Cells[3].Text;
ds.Tables[0].Rows.Add(row);
}
you'll need a combination of aspx markup and code-behind:
aspx:
<asp:GridView ID="gvSample" runat="server"
DataKeyNames="CustomerID"
onselectedindexchanged="gvSample_SelectedIndexChanged">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton ID="btnSelect" runat="server" CommandName="Select" Text="Select"></asp:LinkButton>
<asp:Image ID="imgSelect" runat="server" ImageUrl="~/imgs/whatever.jpg" Visible="false" />
</ItemTemplate>
code-behind:
protected void gvSample_SelectedIndexChanged(object sender, EventArgs e) {
LinkButton linkButton = gvSample.SelectedRow.Cells[0].FindControl("btnSelect") as LinkButton;
Image imgWhatever = gvSample.SelectedRow.Cells[0].FindControl("imgSelect") as Image;
linkButton.Enabled = false;
linkButton.Visible = false;
imgWhatever.Visible = true;
}
so, in the ItemTemplate markup of the GridView, specify the image you want to replace the Select button with but make it invisible, then disable the Select button in place of the image by swapping visibility between both objects within the event handler method gvSample_SelectedIndexChanged in the code-behind, which is what gets triggered upon clicking Select button. Since FindControl returns objects of type Control you'll have to cast to the LinkButton type of your Select button.

Resources