asp:Hyperlink returning null in Formview - c#

I have a asp:Hyperlink set up in my applications' formview and a label
<br />
<b>Posting Site:</b>
<asp:Label ID="AppleLabel" runat="server" Text='<%# Bind("Apple") %>' />
<br />
<asp:HyperLink ID="hplPostIt" Text="Text" runat="server"/>
and in my Page_Load event I attempt to find the label and the hyperlink:
Label Apple = FormView1.FindControl("Apple") as Label;
HyperLink hplPostIt = FormView1.FindControl("hplPostIt") as HyperLink;
Then I try to use an if statement to change the NavigateURL property of the hyperlink based on the text of the label and Visual Studio complains that the object reference is not set. Here is my if else condition:
if (!Page.IsPostBack)
{
lblRow.Text = Request.QueryString["num"];
hplPostIt.Text = "Eat Now";
if (Fruit.Text == "Fruit")
{
hplPostIt.NavigateUrl =
"https://www.mysite.com/Fruit/Apples.aspx?Season=" +
SeasonLabel.Text + "&Color_Date=" + TypeLabel.Text +
"&num=" + SeasonLabel.Text;
}
else
{
hplPostIt.NavigateUrl =
"Fruit/Apples.aspx?Season=" + SeasonLabel.Text +
"&Color_Date=" + TypeLabel.Text + "&num=" + SeasonLabel.Text;
}
}
Edited
I left out the Postback check
I have also tried using this in a protected void FormView1_DataBound(object sender, EventArgs e) with no luck

I made lot of assumptions and added some code to make a working example for you. In case you think I did not get you, please add some more information by commenting on my answer of editing your question!
Assumptions
Class Fruit - representing your dataContainer - simplified it, to store a name
on Page_Load I bound some demo values
added a paging functionality to provide a working example
Solution
I used a customMethod(..) to bind on property NavigateUrl
added string.Format(..) to concat your strings
Still unclear
Where do SeasonLabel and TypeLabel come from?
Markup
<form id="form1" runat="server">
<div>
<asp:FormView ID="fvFruits" runat="server" AllowPaging="True"
OnPageIndexChanging="fvFruits_PageIndexChanging">
<ItemTemplate>
<asp:Label ID="lblFruit" runat="server" Text='<%# Bind("Name") %>' />
<asp:HyperLink ID="hplPostIt" Text="yourText"
NavigateUrl='<%# customMethod(Eval("Name")) %>' runat="server"/>
</ItemTemplate>
</asp:FormView>
</div>
</form>
CodeBehind
protected void Page_Load(object sender, EventArgs e)
{
// demo purposes to add some data
if (!Page.IsPostBack)
bindDemoData();
}
private void bindDemoData()
{
List<Fruit> fruits = new List<Fruit>();
fruits.Add(new Fruit() { Name = "Apple" });
fruits.Add(new Fruit() { Name = "Banana" });
fruits.Add(new Fruit() { Name = "Orange" });
fvFruits.DataSource = fruits;
fvFruits.DataBind();
}
/// <summary>
/// Custom method to check for a given parameter value, which will be given
/// by the dataBinding within markup code.
/// You might even pass more parameter values
/// </summary>
/// <param name="fruit">the name of the fruit</param>
/// <returns>custom link for each given fruitName</returns>
public string customMethod(object fruit)
{
if (fruit != null)
{
string fruitName = fruit.ToString();
// insert custom binding here!
string url = "https://www.mysite.com/Fruit/";
if (fruitName == "Apple")
url += "Apples.aspx";
else if (fruitName == "Banana")
url += "Banana.aspx";
else if (fruitName == "Orange")
url += "Orange.aspx";
/*else
url += "defaultFruit.aspx";; // up to you*/
// can't see where SeasonLabel and TypeLabel are defined??? please add a comment if I did get you wrong
url += string.Format("?Season={0}&Color_Date={1}&num={2}", SeasonLabel.Text, TypeLabel.Text, SeasonLabel.Text);
//uncomment this line and comment out the line above to get a working example
//url += string.Format("?Season={0}&Color_Date={1}&num={2}", "a", "b", "c");
return url;
}
return "https://www.mysite.com/error.aspx"; // probably - but up to you
}
protected void fvFruits_PageIndexChanging(object sender, FormViewPageEventArgs e)
{
fvFruits.PageIndex = e.NewPageIndex;
bindDemoData();
}
// demo data container
public class Fruit
{
public string Name { get; set; }
}
Result Pic

First of all, use string.Format to format a url string
hplPostIt.NavigateUrl = string.Format("https://www.mysite.com/Fruit/Apples.aspx?Season={0}&Color_Date={1}&num={2}", SeasonLabel.Text, TypeLabel.Text, SeasonLabel.Text);
Second
You don't need FindControl to access to hplPostIt, if it located directly on Page. See "youpagename.aspx.design.cs" to find control declaration
Third
Probably null reference exception thrown by one of text control (SeasonLabel, TypeLabel)

Have you tried running it in the formview databound event rather than page load?
Something like:
<asp:FormView ID="FormView1" runat="server" OnDataBound="FormView1_DataBound" ...>
and in the code behind
protected void FormView1_DataBound(object sender, EventArgs e)
{
Label Apple = FormView1.FindControl("Apple") as Label;
HyperLink hplPostIt = FormView1.FindControl("hplPostIt") as HyperLink;
// etc.
}
As a workaround
<asp:HyperLink ID="hplPostIt" runat="server" NavigateUrl='<%# getLink(Eval("Apple")) >' />
Then
protected string getLink(object obj)
{
string fruit = obj.ToString();
// if else with fruit string.
}

Related

ASP.net listview with state

I have a dynamic list in ASP.net front end. User can click a button and add as many entries as it wants.
I'm using ViewState to save this data:
if(ViewState["items"] != null)
{
ListItems.DataSource = ViewState["items"];
}
ListItems.DataBind();
And there is a callback as follows:
protected void AddItemClick(object sender, EventArgs e)
{
List<UserEntry> ue;
if (ViewState["items"] == null)
{
ue = new List<UserEntry>();
}
else
{
ue = (List<UserEntry>)ViewState["items"];
}
ue.Add(new UserEntry());
ViewState["items"] = ue;
}
It's working fine, the problem is that, every time I add a new item, I loose any data I've entered in the other rows. How can I keep this information?
Edit:
I'm calling it from the .aspx page:
<asp:ListView ID="ListItems" class="block" SortExpression="DataType" ItemStyle-Wrap="false" runat="server">
<ItemTemplate >
<table>
<tr>
<asp:TextBox ID="Name" runat="server" class="inline" Text='<%# Eval("text") %>'></asp:TextBox>
</tr>
</table>
</ItemTemplate>
</asp:ListView>
Thanks in advance
Where are you calling this method? Are you calling in the same page? Before you construct the List you might be assigning to ListItems control.
protected void AddItemClick(object sender, EventArgs e)
{
List<UserEntry> ue;
if (ViewState["items"] == null)
{
ue = new List<UserEntry>();
}
else
{
ue = (List<UserEntry>)ViewState["items"];
}
ue.Add(new UserEntry());
ViewState["items"] = ue;
ListItems.DataSource = ue;
ListItems.DataBind();
}
In this line, you can assign the collection to List and bind while adding in the ViewState.
There could be several points to check:
If you are assigning the values to ViewState on Page_Load then you might not be checking if it is a postback or not to overcome it you could just simply do the values assignment part to ListItems in an if condition: if(!Page.IsPostback){/* do stuff */ }
You might want to bind the ListItems each time you modify your list
You Could simply tweak with your code to see where the issue is nobody can help you investigate your code better than you!
Or finally, you may want to skip the ViewState at all, what you can do is:
protected void AddItemClick(object sender, EventArgs e)
{
List<UserEntry> ue = (List<UserEntry>)ListItems.DataSource;
if(ue == null)
{
ue = new List<UserEntry>();
}
ue.Add(new UserEntry());
ListItems.DataSource = ue;
ListItems.DataBind();
} // Just an idea though

How do I select a checkbox bound to a checkbox control from within c# code?

BillingEntity = (string)rdr["BillingEntity"];
string[] split = BillingEntity.Split(',');
for (int i = 0; i < split.Length; i++)
{
split[i] = split[i].Trim();
if (split[i] == "Clinic")
{
BillingEntityCheckBox.Items[i].Checked = true;
Session["billingEntitySessionVar"] = Session["billingEntitySessionVar"]
+ " Clinic";
}
How can I check an item in a checkbox list from the underlying code?
I know with a single checkbox you use checkbox.checked = true. I had that working fine in my code, but I need to link the checkboxes together in a control so that I can trigger an event based on whether any of them has been changed by the user.
To give a little background, I'm pulling in data from a SQL database and outputting to the user interface through a WebForm.
I think you're missing the concept of databinding, is this what you're looking for?:
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
string[] myStrings = new string[] { "Example Value", "Not a Thing", "Many Things", "All the Thing" };
cblThingy.DataSource = myStrings;
cblThingy.DataBind();
}
protected void btnPushMe_Click(object sender, EventArgs e)
{
//for all the things
foreach(ListItem itemThing in cblThingy.Items)
{
//set a default of not selected
itemThing.Selected = false;
//if the text is the same
//you can have any check you like here
if (itemThing.Text == txtThing.Text)
//say that it's selected
itemThing.Selected = true;
}
}
}
^The "code behind"
<asp:Label ID="lblThing" runat="server" Text="If you type the text and push the button the thing with select." />
<asp:TextBox ID="txtThing" runat="server" Text="Example Value" />
<asp:Button ID="btnPushMe" runat="server" Text="Push My Button" OnClick="btnPushMe_Click" />
<asp:CheckBoxList ID="cblThingy" runat="server" />
^The webform xml
Hopefully that helps!
p.s. I think it would be a good idea to make a readonly property on the BillingEntity type, which would return a bool which does the check for "clinic" inside that class, making it more object oriented..

On Button Click Does Not Fire Up The PostBackUrl Once

This seems to be an easy one but got stuck on it last few hours. I've a search button that fires up PostBackUrl. The issue is it only fires up when I click the search button for the second time. Here what I did:
Default.aspx.cs:
protected void Page_Load(object sender, EventArgs e)
{
Page.Title = "View Cities - CcmApp";
if (!IsPostBack)
{
BindGridView(0);
BindPager(0);
GetCountries();
}
}
protected void SearchButton_Click(object sender, EventArgs e)
{
City aCity = new City();
aCity.CityName = nameTextBox.Text;
if (nameTextBox.Text.Length == 0 && radioCityName.Checked == true)
{
labelMsg.Visible = true;
labelMsg.Text = "No search term given";
}
else
{
SearchButton.PostBackUrl = GetDefaultUrl();
}
BindGridView(0);
BindPager(0);
}
public string GetDefaultUrl()
{
return "SearchCity.aspx?SearchTerm=" + nameTextBox.Text;
}
Default.aspx:
<asp:LinkButton ID="SearchButton" runat="server" Text="Search" ValidationGroup="vdGroup"
CssClass="btn btn-primary" OnClick="SearchButton_Click"></asp:LinkButton>
I am not sure what causes it click second time to get the url. Is there any way to get over it?
Note: I am expecting to get the following output in the url -
http://localhost:1234/UI/SearchCity.aspx?SearchTerm=a. But works only on second button click. When I click for the first time, I get this - http://localhost:1234/UI/SearchCity.aspx
The PostBackUrl url on the button is only set AFTER the first PostBack. If you would set it in Page_Load for example you will see that it will work on the first PostBack.
If you want the ?SearchTerm= in the url only when there is content in nameTextBox you could use Response.Redirect or accept that there is no data in ?SearchTerm=.
Better still check on the Clientside if nameTextBox has text and prevent the button click using a Validator.
<asp:LinkButton ID="LinkButton1" runat="server" PostBackUrl="/Default.aspx?SearchTerm=" ValidationGroup="mySearch">Search</asp:LinkButton>
<asp:CustomValidator ID="CustomValidator1" runat="server" ControlToValidate="nameTextBox" ClientValidationFunction="checkLength" ValidateEmptyText="true" ErrorMessage="Min. 3 characters required" ValidationGroup="mySearch"></asp:CustomValidator>
<script type="text/javascript">
function checkLength(oSrc, args) {
var v = document.getElementById("<%=nameTextBox.ClientID %>").value;
if (v.length < 3) {
args.IsValid = false;
} else {
$("#<%=LinkButton1.ClientID %>").attr("onclick", $("#<%=LinkButton1.ClientID %>").attr("onclick").replace("?SearchTerm=", "?SearchTerm=" + v));
args.IsValid = true;
}
}
</script>

how can find every item INFO inside a repeater (in ItemCommand event) - repeater datasource is a List<> collection

i have a list collection like below :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace FileExplorer.Classes
{
public class NewAddedFiles
{
public string FileName { get; set; }
public string FilePath { get; set; }
public DateTime FileCreationDate { get; set; }
}
}
private void GetFilesFromDirectory(string PhysicalPath)
{
DirectoryInfo Dir = new DirectoryInfo(PhysicalPath);
FileInfo[] FileList = Dir.GetFiles("*.*", SearchOption.AllDirectories);
List<NewAddedFiles> list = new List<NewAddedFiles>();
foreach (FileInfo FI in FileList)
{
NewAddedFiles NewAddedFile = new NewAddedFiles();
string AbsoluteFilePath = FI.FullName;
string RelativeFilePath = string RelativeFilePath = "~/" + (AbsoluteFilePath.Replace(Request.ServerVariables["APPL_PHYSICAL_PATH"], String.Empty)).Replace("\\", "/");
NewAddedFile.FileName = FI.Name;
NewAddedFile.FilePath = RelativeFilePath;
NewAddedFile.FileCreationDate = FI.CreationTime;
list.Add(NewAddedFile);
}
Repeater1.DataSource = list;
Repeater1.DataBind();
}
my repeater in aspx is like below :
<asp:Repeater ID="Repeater1" runat="server"
onitemcommand="Repeater1_ItemCommand">
<ItemTemplate>
<asp:Image ID="imgArrowIconInsideRepeater" runat="server" ImageUrl="~/Images/Login/ArrowIcon.png" />
<asp:LinkButton ID="lbFile" runat="server" CommandName="lbFile_Click" CssClass="lbFileInRepeater"><%# Eval("FileName")%></asp:LinkButton>
<br />
<asp:Label ID="lblFileCreationDate" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "FileCreationDate", "{0:yyyy/MM/dd - tt h:m:s}") %>'
CssClass="lblFileCreationDateInRepeater"></asp:Label>
<div class="EmptyDiv">
</div>
</ItemTemplate>
</asp:Repeater>
and Item_Command Of repeater in code behind :
protected void Repeater1_ItemCommand(object source, RepeaterCommandEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
NewAddedFiles currentItem = (NewAddedFiles)e.Item.DataItem;
switch (e.CommandName)
{
case "lbFile_Click":
{
if (HttpContext.Current.Session["User_ID"] != null)
{
Response.Redirect("~/HandlerForRepeater.ashx?path=" + currentItem.FilePath);
}
else
{
ScriptManager.RegisterStartupScript(this, this.GetType(), "alert", "alert('a');", true);
}
break;
}
default:
{
break;
}
}
}
}
my problem is currentItem is always null , when i click on every link button inside repeater!
i want to get FilePath of every link button inside repeater!
how can i do that ?
thanks in advance
From memory (and reinforced from Google searches), ItemCommand is one of the events that loads data from the ViewState. Once this happens, your original DataItem references do not exist anymore.
If you want to retrieve values from that item, as clunky as it sounds, you'll need to add a HiddenField to your Repeater ItemTemplate, like so:
<asp:HiddenField ID="filePath" runat="server" Value='<%# DataBinder.Eval(Container.DataItem, "FilePath")' />
and then replace this line:
Response.Redirect("~/HandlerForRepeater.ashx?path=" + currentItem.FilePath);
with these two lines:
HiddenField filePath = (HiddenField) e.Item.FindControl("filePath");
Response.Redirect("~/HandlerForRepeater.ashx?path=" + filePath.Value);
e.Item.DataItem is only available during the databinding event. You will need to use another method to extract the information you need. Put your primary key into a hidden field, retrieve that value, then
try something like
RepeaterItem ri = e.Item;
HiddenField pk = (HiddenField)ri.FindControl("pk");
int FileID = Convert.ToInt32(pk.Value);
// Create a NewAddedFiles object using the File's FileID (or whatever you have) and get the Filepath from that
I'm sure someone else will have a better answer than mine, but I can offer a workaround while you wait for that. You could add a hidden field that contains the FileName, and then use e.Item.FindControl("HiddenFieldFileName") to get at the value.
In most cases there is no need for a hidden field, simply put the data value you need in the CommandArgument property of the button:
<asp:LinkButton ID="lbFile" runat="server" CommandName="lbFile_Click" CommandArgument='<%# Eval("FilePath")%>' CssClass="lbFileInRepeater"><%# Eval("FileName")%></asp:LinkButton>
Then in the ItemCommand() event retrieve the value:
string filePath = e.CommandArgument.ToString()
You may need to HTML encode the value assigned to CommandArgument so it won't break the HTML.
Suggest you don't set the CommandName value as if it is the name of an event handler method "lbFile_Click". Instead use a name to indicate the intended outcome or action, in this case "Navigate".

Passing two values through CommandArgument and splitting it

I'm using the commandArgument property of the LinkButton ( Which is wrapped inside a repeater ) to pass two values -as one string- to a second repeater then I try to split them into two values, So I could use them as parameters in my ADO.NET Code (SqlCommand Parameters)....after testing my queries don't return any results but If I passed fixed values for the parameter or change the source of the parameter (just for test from a textbox or querystring or something) I get my results, so I think the problem is in splitting.
I Conduct some arugment values from the ArgumentCommand property of the LinkButton -which is wrapped inside a repeater:
<ItemTemplate>
<asp:LinkButton id="sort_lnkbtn" Text='<%# Eval("value")%>'
CommandArgument='<%#string.Format("{0}|{1}",Eval("arrange_by_id"),Eval("value"))%>' runat="server">
</asp:LinkButton>
</ItemTemplate>
Then I receive these values and cut them into two pieces of information:
string sortByAndArrangeBy = (e.CommandArgument).ToString();
char[] separator = { '|' };
string[] sortByAndArrangeByArray = sortByAndArrangeBy.Split(separator);
Now the ado.net code uses this values as a
using (SqlConnection cn1 = new SqlConnection(ConfigurationManager.ConnectionStrings["testConnectionString"].ConnectionString))
{
using (SqlCommand cm1 = new SqlCommand("SELECT [name] FROM brands WHERE (name like #SearchString + '%' )", cn1))
{
cm1.Parameters.Add("#SearchString", System.Data.SqlDbType.Char);
cm1.Parameters["#SearchString"].Value = sortByAndArrangeByArray[1];
cn1.Open();
using (SqlDataReader dr1 = cm1.ExecuteReader())
{
List_rpt.DataSource = dr1;
List_rpt.DataBind();
}
}
}
Here is a simple solution:
Wrap your item template for the repeater in a control. The control will have the same markup as your item template without the bindings:
Control Markup:
<div>
<asp:LinkButton ID="LnkBtnSort" runat="server" Text="Sort" OnClick="LnkBtnSort_Clicked"/>
</div>
Control Code:
public class SomeControl
{
public event EventHandler Click;
public string ArrangeById
{
set { ViewState["byid"] = value; }
get { return ViewState["byid"].ToString(); }
}
public string Value
{
set { ViewState["val"] = value; }
get { return ViewState["val"].ToString(); }
}
protected void LnkBtnSort_Clicked(object sender, EventArgs e)
{
if( Click != null )
{
this.Click(this, EventArgs.Empty);
}
}
}
So now in the repeater all you have to do is bind an instance of that control to the Container.DataItem:
<ItemTemplate>
<ctrl:SomeControl
ID="someControl"
runat="server"
OnClick="SomeControl_Clicked"
ArrangeById='<%# Eval("arrange_by_id") %>'
Value='<%# Eval("value") %>' />
</ItemTemplate>
The page/control that has the repeater will have one simple method:
protected void SomeControl_Clicked(object sender, EventArgs e)
{
//Here cast the sender to the type of control you made:
SomeControl ctrl = (SomeControl)sender;
string byId = ctrl.ArrangeById;
string val = ctrl.Value;
}
Note: this code may not be 100% correct but it illustrates the point. The flow is simple - the control binds its public properties to whatever you need to bind. When the link is clicked (inside your control) the control doesn't propagate this event to the page. Instead it fires its own event (Click) thus sending a signal to the page that an event occured. however by doing so, it changes the source of the event to itself instead of the actual link button. The page handles the event and everyone is happy.
This way you don't have to care what the CommandArgument is... If this comes up empty, it means that either your data source is empty... or something else happened in the code.

Categories

Resources