I am getting a null reference exception when trying to FindControl on a button. I have a shopping cart setup where I have a content page (.aspx) based on a master page. On the content page, there is a placeholder control in which I am dynamically adding user controls (one control per product, each with an 'add to cart' button inside it).
When the user clicks button to add item to cart, I can add it to the cart successfully, then I am counting the number of items in the cart and if more than 1, trying to show the 'checkout' button, or if none in the cart hide it.
I am using FindControl, but getting a null reference error. Why can't it find the checkout button? My current code is below:
MASTER PAGE (template.Master):
<%# Master Language="C#" AutoEventWireup="true" CodeBehind="template.master.cs" Inherits="OUWP.template" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head runat="server"></head>
<body>
<form id="form1" runat="server">
<asp:ContentPlaceHolder ID="m_cph_body" runat="server"></asp:ContentPlaceHolder>
</form>
</body>
</html>
CONTENT PAGE (shop.aspx)
<%# Page Title="" Language="C#" MasterPageFile="~/template.Master" AutoEventWireup="true" CodeBehind="shop.aspx.cs" Inherits="OUWP.shop" %>
<%# MasterType VirtualPath="~/template.Master" %>
<asp:Content ID="Content2" ContentPlaceHolderID="m_cph_body" runat="server">
<asp:PlaceHolder ID="Catalogue" runat="server">
<!-- this is where the user controls are dynamically generated-->
</asp:PlaceHolder>
<asp:Panel ID="pnl_Basket" runat="server">
<div>
<asp:LinkButton ID="lbtnCheckout" runat="server">Continue to Checkout</asp:LinkButton>
</div>
</asp:Panel>
</asp:Content>
USER CONTROL PAGE (PurchasableProduct.ascx)
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="PurchasableProduct.ascx.cs" Inherits="OUWP.CustomControls.PurchasableProduct" %>
<asp:UpdatePanel ID="udpBody" runat="server">
<ContentTemplate>
<asp:Panel ID="pnlPurchasableProduct" runat="server">
<asp:LinkButton ID="lbtnAddLine" runat="server" OnClick="lbtnAddLine_Click"></asp:LinkButton>
</asp:Panel>
</ContentTemplate>
<Triggers>
<asp:PostBackTrigger ControlID="lbtnAddLine" />
</Triggers>
</asp:UpdatePanel>
USER CONTROL CODE BEHIND (PurchasableProduct.ascx.cs)
protected void lbtnAddLine_Click(object sender, EventArgs e)
{
// try to find checkout button on parent page of control
System.Web.UI.Page page = (System.Web.UI.Page)this.Page;
LinkButton Target1 = (LinkButton)page.FindControl("lbtnCheckout");
// count the items in the cart (saved in session variable)
DataTable dt = (DataTable)Session["varDataTableCart"];
Int32 ItemCount = 0;
Int Line Quantity = 0;
foreach (DataRow dr in dt.Rows)
{
Int32 LineQuantity = Convert.ToInt32(dt.Rows[dt.Rows.IndexOf(dr)]["Quantity"].ToString());
ItemCount = ItemCount + LineQuantity;
}
// if 1 or more items in cart, try to make button visible
if (ItemCount > 0)
{
Target1.Visible = true;
}
// otherwise no items in cart, so try to hide checkout button
else
{
Target1.Visible = false;
}
}
I have also tried to get at it through the master page using the code below but that didn't work either:
MasterPage mp1 = (MasterPage)page.Master;
LinkButton Target1 = (LinkButton)mp1.Page.FindControl("lbtnCheckout");
Ok so by pure luck I tried this code and it worked and found my button. Using 'parent' of the current control.
LinkButton Target1 = (LinkButton)this.Parent.FindControl("lbtnCheckout");
Related
I have been struggling with accessing a control in master page from a web method (or any static method for that matter).
I have a bootstrap-styled drop down in master page that list user's favorites. Items in this drop down are populated using a repeater that reads list of favorites for current user from DB and populates the drop down.
On the main page that uses this master page there are a number of reports with an "Add to favorites" button. To do this client side, I added an onclick event to button, it calls a javascript function that calls a web method to store this info (User ID, URL) in database. This part is fine. The problem is that then I need to update the dropdown (rebind the repeater).
Here is what I have and what I have tried:
In master page:
<%# Master Language="C#" AutoEventWireup="true" CodeBehind="Site.Master.cs" Inherits="EA.SiteMaster" %>
....
<asp:ScriptManager runat="server" ID="ScriptManager1" EnablePageMethods="true" />
....
<ul class="dropdown-menu" role="menu">
<asp:Repeater runat="server" ID="rptFavorites" OnItemDataBound="rptFavorites_ItemDataBound">
<ItemTemplate>
<li>
<asp:LinkButton runat="server" ID="lbFavLink" /><span class="glyphicon glyphicon-heart"></span>
</li>
</ItemTemplate>
</asp:Repeater>
</ul>
in Default.aspx:
<%# Page Title="Home Page" Language="C#" MasterPageFile="Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="EA._Default" %>
<%# MasterType virtualpath="Site.master" %>
....
function addFavorite(sURL, sFriendlyName) {
// I added this to get the routing working properly
var path = PageMethods.get_path() + '.aspx';
PageMethods.set_path(path);
PageMethods.AddUserFavorite(sURL, sFriendlyName, onSucceeded, onFailed);
}
function onSucceeded(result, userContext, methodName) {
alert(result);
}
function onFailed(result, userContext, methodName) {
alert(result);
}
....
<button type="button" class="btn btn-primary btn-xs" id="btnMPP" onclick="addFavorite('http://blahblah.com/IV/SomeReport.html','Some Report')" ><i class="fa fa-heart-o" aria-hidden="true"></i></button>
in Default.aspx.cs:
[System.Web.Services.WebMethod]
public static string AddUserFavorite(string sURL, string sFriendlyName)
{
string sMsg = string.Empty;
string sUserID = HttpContext.Current.Session["UserID"].ToString();
Favorites oFavorite = new Favorites();
oFavorite.FavoritesURL = sURL;
oFavorite.FavoritesFriendlyName = sFriendlyName;
oFavorite.UserID = sUserID;
int iRet = Favorites.AddFavrites(oFavorite);
if (-1 == iRet)
sMsg = "Failed to add to favorites list";
else
{
sMsg = "\"" + sFriendlyName + "\" (" + sURL + ") was added to your favorites list";
UpdateMaster();
}
return sMsg;
}
private static void UpdateMaster()
{
Page page = (Page)HttpContext.Current.Handler;
MasterPage mp = page.Master; <--- Always null
Repeater rptFavorites = mp.FindControl("rptFavorites") as Repeater;
if (rptFavorites != null)
{
// rebind repeater here
}
}
Any ideas on how I can achieve this is greatly appreciated. Of course, I can change the "Add to Favorites" to an ASP LinkButton and no issues, but just need to know how this approach can be done; if it can.
I don't think you need this code to access your repeater.
Page page = (Page)HttpContext.Current.Handler;
MasterPage mp = page.Master; <--- Always null
You just need to tell it to look for it in the MasterPage.
Try it this way.
(Repeater) rpt = (Repeater) Master.FindControl("rptFavorites");
When I attached My UserControl(contains Literal control, imageButton Control, labels, click event with imageButton control)
on the main page(default.aspx) dynamically,
Each ImageButton click Event of Usercontrol doesn't firing,
only refreshed.
Moreover, Breaking Point that I settled on the first line of click event logic of ImageButton
Doesn't work.
It seems doesn't pass its click event.
Please Help me
Below is UserControl's back code
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="ContentHolder.ascx.cs" Inherits="TISSWeb.ContentHolder" %>
<asp:Panel ID="Panel2" runat="server" BorderColor="#3399FF" BorderStyle="Solid"
BorderWidth="1px" width="100%">
<asp:ImageButton ID="ImageButton1" runat="server" Width="16px"
onclick="ImageButton1_Click" />
<asp:ImageButton ID="ImageButton2" runat="server" onclick="ImageButton2_Click" Width="16px"/>
<asp:Label ID="Label1" runat="server" Text="Title"></asp:Label>
<asp:ImageButton ID="ImageButton4" runat="server" ImageUrl="~/Images/linknew.gif" />
<asp:Label ID="Label2" runat="server" Text="Date"></asp:Label>
<br />
<asp:Panel ID="Panel3" runat="server" style="overflow:hidden;height:60px;">
<asp:Literal ID="Literal1" runat="server"></asp:Literal>
</asp:Panel>
</asp:Panel>
//below is C#(asp.net) Code
protected void ImageButton2_Click(object sender, ImageClickEventArgs e)
{
//below if is where I settled the Break Point
if (starred == "1")
{
starred = "0";
ImageButton2.ImageUrl = "~/Images/star-off.png";
String sql = "some sql";
mysql.ExecuteNonQuery(sql);
}
else
{
starred = "1";
ImageButton2.ImageUrl = "~/Images/star-on.png";
String sql = "some sql";
mysql.ExecuteNonQuery(sql);
}
}
//Below is Main page's back code
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebForm1" %>
<%# Register src="ContentHolder.ascx" tagname="ContentHolder" tagprefix="ContentHolder" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:Panel ID="Panel1" runat="server" BackColor="#006699" Height="35px"
<asp:Label ID="Label1" runat="server" Text="Subscription"></asp:Label>
</asp:Panel>
</form>
</body>
</html>
//below is C#(ASP.net) Code of main page
protected void Page_Load(object sender, EventArgs e)
{
DataTable SrcData = mysql.executeSelect("Some SQL");
for (int i = 0; i < dt.Rows.Count; i++)
{
ContentHolder uc = (ContentHolder)LoadControl("ContentHolder.ascx");
form1.Controls.Add(uc);
}
}
ok so i have tested your code ( with miner exception that you get there )
it works ( i removed all the images except ImageButton2 ) for debugging and it works.
so i would suggest that you do the same remove all images and stay with one, test it my guess
it will work, then add one other img and test, i can tell your very new to asp.net because you are using the design view to shape your page and that's why u get a lot of none breakabl space in your code
i would really recommend to not work like this because you will never learn to code HTML properly like this, take your time dont skip steps read about HTML CSS JS to better understand
when client tech is better then server and vice versa, but thats my 50 cents :)
any way enjoy.
I am using an combobox with some values and AutoPostBack = true, the page does not refresh.
I have a selectedIndexChanged event as well.
I managed to get the selectedValue and I would like to show this in a TextBox.
In the selectedIndexChanged event I did:
textBox1.Text = selectedValue.ToString();
When I inspect this textbox element with Google Chrome I can see the value is set in the TextBox.
But in the browser the value isn't shown, still an empty TextBox.
Do you guys have any clue why this could happen?
Thanks!
How do you populate items for ComboBox? If dynamically via On-Load event then make sure that method that adds items does not run on PostBack.
Here is your working code buddy.
Don't forget ToString method.
<%# Page Language="C#" AutoEventWireup="true" CodeFile="Test2.aspx.cs" Inherits="Test2" %>
<%# Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server"></asp:ToolkitScriptManager>
<asp:ComboBox ID="ComboBox1" runat="server" AutoPostBack="True" OnSelectedIndexChanged="ComboBox1_SelectedIndexChanged">
<asp:ListItem>Item1</asp:ListItem>
<asp:ListItem>Item2</asp:ListItem>
<asp:ListItem>Item3</asp:ListItem>
</asp:ComboBox>
<asp:TextBox runat="server" ID="textBox1"/>
</div>
</form>
</body>
</html>
and code
public partial class Test2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void ComboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
textBox1.Text = ComboBox1.SelectedValue.ToString();
}
}
I want to double click on a cell of a gridpanel an call another
action/view with extra parameter example:
The gridpanel is in .../Student and I want to show the details of one
student in another page ex: /Student/Detail/1 double clicking on his
name, id, or wherever data is on his record.
Sorry for the bad english
I tried this
#(
Html.X().GridPanel()
.Title("Students")
.Width(550)
.Height(200)
.ForceFit(true)
.Store(Html.X().Store().Model(Html.X().Model()
.Fields(fields =>
{
fields.Add(Html.X().ModelField().Name("StudentID"));
fields.Add(Html.X().ModelField().Name("LastName"));
fields.Add(Html.X().ModelField().Name("FirstMidName"));
fields.Add(Html.X().ModelField().Name("EnrollmentDate"));
}
)
).DataSource(Model)
).ColumnModel(
Html.X().Column().Text("Student ID").DataIndex("StudentID"),
Html.X().Column().Text("Last Name").DataIndex("LastName"),
Html.X().Column().Text("First Name").DataIndex("FirstMidName"),
Html.X().DateColumn().Text("Enrollment").DataIndex("EnrollmentDate")
).DirectEvents(de =>
{
de.CellDblClick.Url = "Edit"; // also tried
de.CellDblClick.Action = "Edit";
de.CellDblClick.ExtraParams.Add(1); //static
later I'll add the StudentID here
}
)
)
The gridpanel show the data without problem but when I doubleclick on a
cell this is the request that it's sended
localhost:10782/Student/Edit?_dc=1359052548829
instead of this
localhost:10782/Student/Edit/1
I can suggest to manage an URL with a Before handler.
To remove "?dc..." from an URL, please set up DisableCaching="false".
<%# Page Language="C#" %>
<%# Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>
<!DOCTYPE html>
<html>
<head runat="server">
<title>Ext.NET v2 Example</title>
<script>
var counter = 1;
</script>
</head>
<body>
<ext:ResourceManager runat="server" />
<ext:Button runat="server" Text="Test">
<DirectEvents>
<Click Url="Some URL" Before="o.url = o.rawUrl + counter++;" DisableCaching="false">
<CustomConfig>
<ext:ConfigItem Name="rawUrl" Value="Controller/Action/" Mode="Value" />
</CustomConfig>
</Click>
</DirectEvents>
</ext:Button>
</body>
</html>
I'm creating multiple DIVs according to database records at my C# behind code. How could I make them runat server ?
Thanks in advance ..
Create and add ASP.NET Panels.
The code
<asp:Panel id="abc" runat="server">
is exactly the same as if you do:
<div id="abc" runat="server">
They render the same, but it's the functionality with other WebControls that the Panel is most used, and the Panel web control gives you more control under code-behind as it exposes more properties.
If you want to access a DIV on serverside, you could also add runat="server". It will be created as HtmlGenericControl.
That's not necessary, just create a HtmlGenericControl and add it to the controls collection:
HtmlGenericControl div = HtmlGenericControl("div")
div.Id = "myid";
this.Controls.Add(div);
Use a custom control that pulls the data and renders it how you would like. Kind of like this:
public class MyDivControl : System.Web.UI.Control
{
private System.Data.DataTable tblMyResults;
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
// Get your Data (or do it on Page_Load if you'll need it more than once
if (tblMyResults != null && tblMyResults.Rows.Count > 0)
{
int iIndex = 0;
foreach (System.Data.DataRow rItem in tblMyResults.Rows)
{
writer.WriteLine("<div id=\"{0}_{1}\">", this.ClientID, iIndex++);
//Whatever content you want here using your rows.
writer.WriteLine("</div>");
}
}
}
}
Then just drop the control on the page where you want it to render.
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="default.aspx.cs" Inherits="Solution.Web.Presentation.pub._default" MasterPageFile="~/ui/master/main.master" %>
<%# Register TagPrefix="custom" Namespace="MyNameSpace" Assembly="MyProjectAssembly" %>
<asp:Content runat="server" ContentPlaceHolderID="cntMain">
<custom:MyDivControl runat="server" />
</asp:Content>
You can use Repeater Control
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<div id="box<%# Eval("ID")%>" runat="server"></div>
</ItemTemplate>
</asp:Repeater>
and bind data from codebehind