I am fairly new to ASP.NET (PHP programmer for 8 years), so please forgive me if my terminology is incorrect.
I am currently grabbing a remote XML file in a repeater XMLDataSource, and the DataFile attribute is being set in the code behind (I have the DataFile dynamically change based on URI parameters such as ?cat=blah etc). This works beautifully and is not a problem.
Within this repeater is a <asp:HyperLink>, whose URL is to be dynamically changed in the code behind as well.
Now to the question:
From the code behind, how can I see if XML nodes are empty, and how can I grab the value of nodes that are not?
I have been on this issue for about 3 days now (hours of searching), however I just cannot figure out something that seems like it should be so simple! Here is the code I currently have, however I am given an error of Object reference not set to an instance of an object for the code behind line that has CreateNavigator();
Hopefully somebody more adept than me with ASP.NET and C# can easily spot the problem or knows of a way I can accomplish this?
Code
<asp:XmlDataSource ID="rssFeed" runat="server"></asp:XmlDataSource>
<asp:Repeater runat="server" DataSourceID="rssFeed" OnItemDataBound="Repeater_ItemDataBound">
<ItemTemplate>
<asp:HyperLink ID="articleURL" Text='<%#XPath("title")%>' runat="server" />
</ItemTemplate>
</asp:Repeater>
Code behind C#
protected void Page_Load(object sender, EventArgs e)
{
// rss variables
var rssSource = "http://websiteurl.com/xmlfeed/";
var rssPath = "rss/channel/item";
var searchQueries = "?foo=bar";
string currCat = Request.QueryString["cat"];
string searchTerms = Request.QueryString["s"];
// insert categories query
if(currCat != null){
searchQueries += "&cat=" + currCat;
}
// insert search query
if(searchTerms != null){
searchQueries += "&s=" + searchTerms;
}
// load RSS file
rssFeed.DataFile = rssSource + searchQueries;
rssFeed.XPath = rssPath;
}
protected void Repeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
XPathNavigator nav = ((IXPathNavigable)e.Item.DataItem).CreateNavigator();
string hyperlinkURL = nav.SelectSingleNode("link").Value;
// removed code here that changes URL to hyperlinkURL to shorten post
}
For those who may be interested in this as well, I found a solution where I can easily check and manipulate xml items.
protected void Repeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
// make sure we are not checking item in ItemHeader or ItemFooter to prevent null value
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem) {
string myVar = XPathBinder.Eval(e.Item.DataItem,"title").ToString();
// utilize and manipulate myVar XML value here
}
}
Related
I tried doing this on the check box list page:
protected void Page_Load(object sender, EventArgs e)
{
(string)Session["name"] = cbl1.Items.Add;
}
but I don't know how to make it work.
You don't really "put a label into" a check box list from another page.
You might say have a check box list on one page, and you want to pass the selection(s) made in the first page, and pass to the 2nd page.
So, say we have a simple check box list of options on page 1
And a button to jump to the next page.
This markup:
<h3>Hotel Options</h3>
<asp:CheckBoxList ID="CheckBoxList1" runat="server"
DataValueField ="ID"
DataTextField="HotelOption" >
</asp:CheckBoxList>
<br />
<br />
<asp:Button ID="Button1" runat="server"
Text="Continue to next page" CssClass="btn" OnClick="Button1_Click" />
And code to load this up:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadCheckBox();
}
void LoadCheckBox()
{
DataTable rstOptions =
MyRst("SELECT ID, HotelOption FROM tblOptions ORDER BY ID");
CheckBoxList1.DataSource = rstOptions;
CheckBoxList1.DataBind();
}
DataTable MyRst(string strSQL)
{
DataTable rstData = new DataTable();
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.Hotels))
{
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
cmdSQL.Connection.Open();
rstData.Load(cmdSQL.ExecuteReader());
}
}
return rstData;
}
And we now have this:
Ok, so now our code for the button.
We will get + save the above selections, and pass to the next page:
protected void Button1_Click(object sender, EventArgs e)
{
Session["MyItems"] = CheckBoxList1.Items;
Response.Redirect("WebForm2.aspx");
}
Ok, now our markup for the 2nd page.
We have this:
<h3>Hotel Options - on next page</h3>
<asp:CheckBoxList ID="CheckBoxList1" runat="server"
DataValueField ="Value"
DataTextField="Text" >
</asp:CheckBoxList>
<br />
Now, we saved the "items list" for the Check box list. The item list has a text and value property (we LOSE the colum name information that the data sourced used was).
So, note how the DataValueField="value" and DataTextField="Text" now.
So, this code:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadCheckBox();
}
void LoadCheckBox()
{
ListItemCollection MyItems = (ListItemCollection)Session["MyItems"];
foreach (ListItem OneItem in MyItems)
{
CheckBoxList1.Items.Add(OneItem);
}
}
And now on 2nd page we have this:
Now it is NOT clear why I can't just bind this passed list directly to the check box list, but I found a foreach loop is required.
Now, it is perhaps not clear, but maybe you ONLY wanted the label text ones selected.
You can do this with this code:
ListItemCollection MyItems = (ListItemCollection)Session["MyItems"];
foreach(ListItem OneItem in MyItems)
{
if (OneItem.Selected)
{
Debug.Print("Label text = " + OneItem.Text);
Debug.Print("Check box value = " + OneItem.Value);
}
}
Output:
Label text = Smoking
Check box value = 1
Label text = Balcony
Check box value = 2
So, keep in mind that a check box list can often have 2 columns of data.
The display "label" or text, or the hidden value.
In my example, the "ID" is the PK value from the database, and I need that.
If you only have one "text" value, and don't care about a hidden database PK value, then often I just set both DataTextField and DataValueField to the SAME column in the database.
And if you using looping, and adding a listitem in code? Then the settings are not the field columns anymore, but Text and Value. You thus still have the ability to have 2 values - the display text, and some key or number value for a checkbox list.
Now perhaps you have two web pages open, and you want to change/set controls in the other web page?
No, you can't do that. Other web pages might say be open to someone's banking web site. You can't mess around with other web pages the user has open, since that would be a MASSIVE security hole, and no one would risk using the world wide web then, right?
Edit: placing the results on a label on the 2nd page
Ok, so the debug.print? That is just a handy debugging way of displaying some code values - only for developers. It really much like using console.log to display value(s) into the console. It certainly not for putting some text into a label (I realy thought that would be crystail clear to you - at a loss as to why you think debug.print has anything of value or is relavent to YOU writing code to put a few text values into a label).
So, ok, on the 2nd page we will have a label and not some check box list.
So, our markup on the 2nd page will now look like this:
<asp:Label ID="Label1" runat="server" Text=""
Font-Bold="true"
Font-Size="Large"
></asp:Label>
And in our page load event, we will have this:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadLabel();
}
void LoadLabel()
{
ListItemCollection MyChoices = (ListItemCollection)Session["MyItems"];
// process selection list from
// previous page - shove reuslts into label
string strChoices = "";
foreach (ListItem OneChoice in MyChoices)
{
if (OneChoice.Selected)
{
if (strChoices != "")
strChoices += ",";
strChoices += OneChoice.Text;
}
Label1.Text = strChoices;
}
}
So, now on first page, we say select this:
And now on 2nd page, we see this:
Of course, we could change our code to display each choice on a new line,
Say this code:
void LoadLabel()
{
ListItemCollection MyChoices = (ListItemCollection)Session["MyItems"];
// process selection list from
// previous page - shove reuslts into label
string strChoices = "";
foreach (ListItem OneChoice in MyChoices)
{
if (OneChoice.Selected)
{
if (strChoices != "")
strChoices += #"<br/>"; // <-- new line in label
strChoices += OneChoice.Text;
}
Label1.Text = strChoices;
}
}
And now we would see this:
So, you can shove results into that label - separated by ",", or whatever.
Or, you can display the choices on a new line as per last example.
How can one achieve the following requirement?
Based on values in the queryString, the requested record must be expanded into its DetailView.
This example uses Entity Framework 6 for accessing data. This means the RadGrid's pageSize, pageIndex and sort information must persist within the call EF makes to the database.
Let's assume the following URL when you arrive at the page containing the RadGrid.
http://localhost:61878/search?pageindex=8&orderid=2871517&pagesize=50
The RadGrid declarative markup would look like this.
<telerik:RadGrid ID="OrdersMasterGrid" runat="server"
AllowPaging="True"
AllowSorting="True"
AutoGenerateColumns="False"
OnNeedDataSource="GridOnNeedDataSource"
OnPreRender="GridPreRender">
Then the PageLoad would look like this. This fires BEFORE the RadGrid's OnNeedDataSource event so it's important to set the correct pageindex and pagesize because that information will flow all the way to the database.
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack == false)
{
OrderID_QueryString = Request.QueryString.GetValue<string>("orderid");
OrdersMasterGrid.MasterTableView.CurrentPageIndex = Request.QueryString.GetValue<int>("pageindex");
OrdersMasterGrid.MasterTableView.PageSize = Request.QueryString.GetValue<int>("pagesize");
}
Programatically expanding the correct row takes place during the OnPreRender event.The GridPreRender eventHandler would look like:
protected void GridPreRender(object sender, EventArgs e)
{
foreach (object gridDataItem in OrdersMasterGrid.MasterTableView.Items)
{
if (gridDataItem is GridDataItem)
{
GridDataItem gdi = gridDataItem as GridDataItem;
if (gdi["OrderID"].Text == OrderID_QueryString)
{
gdi.Expanded = true;
break;
}
}
}
}
Conclusion: Although this example uses the queryString, it might be better to use ViewData, ViewBag or other transparent mechanisms. The pitfall of this approach is if the user decides to bookmark the page, it's going to stop working eventually when the requested orderid does not exist in the data returned by EF6 for the 8th page when pagesize is 50.
I have spend two days trying to figure out the solution to this problem, even tried ExpertExchange and still I can't get a solution. I am a very novice programmer to ASP.Net (using C#) and I DON'T want to use a string/url post
I have a MasterPage of which has a textbox called tbSearchString. It is a simple box that a user can enter something and then it does a Postback to another page SearchResults.aspx So I also have other pages, like Default.aspx that uses the MasterPage.
I have tried nearly everything and have read nearly every post I could find on the net and no mater what the Variables are always Null.
I have use this code on the searchResults loadpage event and Every one of these variables are null, even though I enter a value in the page text box and click the button to postback to the SearchResults page, the only time it works is if I am on the searchResults page and submit.
SearchResults back end page
protected void Page_Load(object sender, EventArgs e)
{
TextBox SearchString;
TextBox SearchString2;
TextBox SearchString3;
TextBox SearchString5;
if (Page.PreviousPage != null) //This is true on every test
{
SearchString = (TextBox)Page.PreviousPage.Master.FindControl("tbSearchString");
SearchString2 = (TextBox)PreviousPage.Master.FindControl("tbSearchString");
SearchString3 = (TextBox)Master.FindControl("tbSearchString");
TextBox LoginControlx = (TextBox)PreviousPage.FindControl("Form1");
if (LoginControlx != null)
{
TextBox SearchString4 = (TextBox)LoginControlx.FindControl("tbSearchString");
}
}
MainWebsite.Master page Code
<asp:TextBox ID="tbSearchString" runat="server"></asp:TextBox>
<asp:Button ID="btnSearch1" runat="server" Text="Search" PostBackUrl="~/SearchResultRentalEquiptment.aspx" />
I don't have anything in the CS backend page
So on the Default.aspx page
nothing special Just the Masterpage and some text content, I enter some text in the textbox goes to the SearchResults page and I can not get the darn value from the Textbox control from the Default or any other page.
What say you wise ones?
how do you redirect your form to search result form? if you are using Response.redirect, the value under Page.PreviousPage.Master.FindControl will be null . Try to use Server.Transfer to see if it works.
Here's one way:
Assuming this is your Master Page code:
<asp:TextBox ID="searchbox" runat="server" /><br />
<asp:Button ID="sendSearch" runat="server" PostBackUrl="~/Results.aspx" Text="Search" />
At the end of the day, it's all about HTTP POST, so in the target page Results.aspx PageLoad:
protected void Page_Load(object sender, EventArgs e)
{
string _foo = Request.Form[this.Master.FindControl("searchbox").UniqueID];
}
Hth....
Check out Session. I use it all the time when I need to get data from one page to another. I'm not currently able to write out a full example for you, but off the top of my head the following should work:
//page1.aspx:
protected void btnSubmit_Click(object sender, EventArgs e)
{
string greetingString = "Hello";
Session["MyValue"] = greetingString;
Response.Redirect("page2.aspx");
}
//page2.aspx:
protected void Page_Load(object sender, EventArgs e)
{
Response.Write(Session["MyValue"].ToString()); //prints "Hello"
}
This question is about a very strange behavior of web controls. Consider the following please.
Scenario
I have a web control which is used to show some data. MyWebControl.ascx file is the following:
<%# Control ViewStateMode="Enabled"
Language="C#"
AutoEventWireup="true"
CodeFile="MyWebControl.ascx.cs"
Inherits="MyWebControl" %>
<div>
<asp:Label ID="MyLabel1" runat="server"></asp:Label>
<asp:Label ID="MyLabel2" runat="server"></asp:Label>
</div>
And code behind MyWebControl.ascx.cs is:
public partial class MyWebControl :
System.Web.UI.UserControl {
protected string str1;
protected string str2;
public string Str1 {
get { return this.str1; }
set { this.str1 = value; }
}
public string Str2 {
get { return this.str2; }
set { this.str2 = value; }
}
protected void Page_Load(object sender, EventArgs e) {
this.MyLabel1.Text = this.str1;
this.MyLabel2.Text = this.str2;
}
}
Well, I use this control inside a ListView of mine in an ordinary web form. This web form is called Default.aspx and, following, I am showing a slice of its code, only the one where the ListView resides in:
<%# Page Title="My page" Language="C#" AutoEventWireup="true"
CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%# Register TagPrefix="my" TagName="MyWC" Src="~/MyWebControl.ascx" %>
...
...
<div>
<asp:ListView ID="MyLV_ListView" runat="server"
EnableViewState="true"
OnPreRender="MyLV_ListView_PreRender"
OnItemDataBound="MyLV_ListView_ItemDataBound">
<ItemTemplate>
<my:MyWC ID="WC_MyWC" runat="server" />
</ItemTemplate>
</asp:ListView>
</div>
This web form code-behind Default.aspx.cs is:
public partial class _Default : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e) {
if (!this.IsPostBack) {
DAO d = new DAO(...); /* This object will contain some data */
/* Data are somehow paged, changing index, we have other data */
/* Please do not worry about paging, it works, problem is another */
d.PageIndex = 0;
this.ViewState["DAO"] = d; /* DAO is serializable */
this.ViewState["PageIndex"] = 0;
Data[] data = d.GetData(); /* Returns an array of objects representing my data */
/* Custom way of storing data in objects */
/* GetData use the PageIndex to get only a range of results */
this.MyLV_ListView.DataSource = data;
this.MyLV_ListView.DataBind();
}
}
protected void MyLV_ListView_ItemDataBound(object sender, ListViewItemEventArgs e) {
if (e.Item.ItemType == ListViewItemType.DataItem) {
((MyWebControl)e.Item.FindControl("WC_MyWC")).Str1 =
((Data)e.Item.DataItem).DataField1;
((MyWebControl)e.Item.FindControl("WC_MyWC")).Str2 =
((Data)e.Item.DataItem).DataField2;
}
}
protected void MyLV_ListView_PreRender(object sender, EventArgs e) {
if (this.IsPostBack)
this.MyLV_ListView.DataBind();
}
// A TreeView will cause the page to reload,
// this is the handler called when a tree node is
// selected, the node is used to change the page
// for showing data in my listview.
protected void MyLVPaging_TreeView_SelectedNodeChanged(object sender, EventArgs e) {
this.ViewState["PageIndex"] = int.Parse(this.MyLVPaging_TreeView.SelectedNode.Value);
((DAO)this.ViewState["DAO"]).PageIndex = (int)this.ViewState["PageIndex"];
// After setting the new index, GetData will return another set of results
this.MyLV_ListView.DataSource = ((DAO)this.ViewState["DAO"]).GetData();
}
}
The problem
What is my problem???
Well, when the page loads for the first time I can see some data in the list view, so everything works.
When I select another page, I cause the page to reload and post back... my ListView will show the correct number of entries but with no data in it. The web control is placed as many times as the number of retrieved data records, but the web control has no data in it.
Debugging results
I conducted some debug sessions and this is what happens, please follow me, this is VERY IMPORTANT to understand I guess.
Page loads for the first time
1) Load page method is executed.
2) ListView's ItemDataBound event handler is executed. Well, given that I have three elements in the Data[] array in the DataSource, the handler is called three times. Inspecting values when proceeding debugging the method, I can see that ((Data)e.Item.DataItem).DataField1 and ((Data)e.Item.DataItem).DataField2 are the correct values retrieved from the bound data source in the ListView.
After the method is executed, the debugger cursor moves to MyWebControl.ascx.cs to the control's Page_Load method. I can see, inspecting variables, that this happens:
protected void Page_Load(object sender, EventArgs e) {
this.MyLabel1.Text = this.str1; // <-- this.str1 has the correct value loaded in the list view itemdatabound event handler.
this.MyLabel2.Text = this.str2; // <-- this.str2 has the correct value loaded in the list view itemdatabound event handler.
}
3) The ListView PreRender method is called.
4) The page shows and everyting is ok!
Page posts back after selecting a node in the TreeView
1) Load page method is executed but it does nothing.
2) MyLVPaging_TreeView_SelectedNodeChanged is executed. Here I can see that everything has the correct value:
protected void MyLVPaging_TreeView_SelectedNodeChanged(object sender, EventArgs e) {
this.ViewState["PageIndex"] =
int.Parse(this.MyLVPaging_TreeView.SelectedNode.Value); // <-- The new page
((DAO)this.ViewState["DAO"]).PageIndex =
(int)this.ViewState["PageIndex"]; // <-- Index saved
// After setting the new index, GetData will return another set of results
this.MyLV_ListView.DataSource =
((DAO)this.ViewState["DAO"]).GetData(); // <-- DataSource is changed
}
3) ListView's ItemDataBound event handler is executed. Well, here, debugging I can see the same as before, I mean, I can see that new values, new Data have been bound to the ListView, in fact I can inspect new values that are assigned to the template item.
Obviously, as before, after the method is executed, the debugger cursor moves to MyWebControl.ascx.cs to the control's Page_Load method.
HERE IS EVIL: I can see the following:
protected void Page_Load(object sender, EventArgs e) {
// Note: inspecting this.IsPostBack I get true!
this.MyLabel1.Text = this.str1; // <-- this.str1 is null and also this.MyLabel1.Text is null.
this.MyLabel2.Text = this.str2; // <-- this.str2 is null and also this.MyLabel1.Text is null. view itemdatabound event handler.
}
Well!!! IT LOSES STATE AND ALSO VALUES
PASSED BY THE LIST VIEW
HANDLER!!!!!!!!!
My question
What the hell is going on???
Notes
1) Please, do not focus too much on how I managed data binding on Load and PreRender events... I have a feeling this is not the error! I guess it is something related to the page lifecycle. However, if you think that this is important detail, let me know.
2) DAO and its function GetData() are a way to let you understand as quick as possible the scenario which is a little bit more articulated, but with the same exact structure I've shown here.
Thank you for your help.
From my comments:
Why don't you move the
this.MyLV_ListView.DataBind() from
PreRender to SelectedNodeChanged? And
why do you need the fields str1 and
str2 in your UserControl? The property
Str1 should get/set this.MyLabel1.Text
and the property Str2should get/set
this.MyLabel2.Text, because the
lables' Text are already stored in
ViewState.
Andry:
... so these kind of settings are not
to be made in the Load?
Me:
you don't need to wait for any event
to happen to set the label's text. The
properties should directly lead to the
corresponding Labels, hence your
fields str1 and str2 are redundant.
They will be disposed at the end of
the Page-Lifecycle as opposed to the
Text property of the Labels which are
stored in ViewState automatically
across postbacks.
When the page first load i have a label who has 0 or 1. Look at the code and you will se what i trying to do. But it don't work because the page allready loaded.
protected void rptBugStatus_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Label lblName = e.Item.FindControl("lblBugStatus") as Label;
if (lblName.Text == "1")
{
lblName.Text = lblName.Text + "Under arbete";
}
else if (lblName.Text == "0")
{
lblName.Text = "Fixad";
}
else { }
}
}
You really want to avoid this type of coding if at all possible. This will quickly grow into an unmaintainable web site.
Query the underlying data instead of GUI elements.
where you put your code? and be cautious e.Item.FindControl("lblBugStatus") as Label; may return null
it's just work fine to fine the control. But i figure out another way to get out the data i want. That i'am going to is fix the xml structur better.
You may have resolved this by now, but I think the problem with the code as you posted it is this:
Label lblName = e.Item.FindControl("lblBugStatus") as Label;
Because you are referencing a control in a repeater, the controls inside each repeater item are named dynamically based on their context. Most likely the name of the control is something like:
"rptBugStatus$repeaterItem0$lblBugStatus"
To find out the exact name, hard code a value, run the page in a browser, and look at the HTML output (via "View Source" in the browser menu). You should be able to scroll down and see your repeater (it will be rendered as a <table> tag), its items, and the controls living inside each item. The IDs/Names will be set and you can copy/paste them into your FindControl method.
Hope this helps,
Nate
Ok, I am taking the assumption you have set this label (assuming to be in the repeater, from your code) to have a value - I have tried databinding to something exactly the same, using the below code.
protected override void OnPreRender(EventArgs e)
{
base.OnLoad(e);
List<string> strList = new List<string>();
strList.Add("1");
rptBugStatus.DataSource = strList;
rptBugStatus.DataBind();
}
protected void rptBugStatus_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Label lblBugStatus = e.Item.FindControl("lblBugStatus") as Label;
// have added this just so we are actually setting the text property on the bug status
// - i have assumed you do this.
lblBugStatus.Text = e.Item.DataItem.ToString();
if (lblBugStatus.Text.Equals("1"))
{
lblBugStatus.Text = lblBugStatus.Text + "Under arbete";
}
else if (lblBugStatus.Text.Equals("0"))
{
lblBugStatus.Text = "Fixad";
}
}
}
With the aspx being
<asp:Repeater runat="server" ID="rptBugStatus" OnItemDataBound="rptBugStatus_ItemDataBound">
<ItemTemplate>
<asp:Label ID="lblBugStatus" runat="server"></asp:Label>
</ItemTemplate>
</asp:Repeater>
And I have no problems.
I get the below on the page.
1Under arbete
I think you are going to need to post more code if you have hidden any away from us :)
Tim