Finding a field on user control form - c#

I have a field 'x' on the user control form which is included on aspx page and that page using SharePoint master page. I'm trying to locate field x on aspx page in my code but it throws "Object ref not set" error. I've tried following but nothing works ,
((TextBox)Page.Master.FindControl("PlaceHolderMain").FindControl("Experience").FindControl("x")).Text
((TextBox)this.FindControl("x")).Text
((TextBox)Page.Master.FindControl("PlaceHolderMain").FindControl("x")).Text
I can locate the field on page source,
<input name="ctl00$PlaceHolderMain$ctl00$x" type="text" value="3" id="ctl00_PlaceHolderMain_ctl00_x" class="textbox" />
Update:-
Previously I was adding user control programmatically on load event of the aspx page,
UserControl uc = (UserControl)Page.LoadControl("Experience.ascx");
experineceForm.Controls.Add(uc);
But by seeing page source I had doubt and thought to add it in design time using following code,
<%# Register TagPrefix="uc" TagName="Experience" Src="Experience.ascx" %>
<div id="experineceForm" runat="server">
<uc:experience id="idExperienceForm" runat="server"/>
</div>
After doing this I'm able to find controls with following code,
((TextBox)Page.Master.FindControl("PlaceHolderMain").FindControl("idExperienceForm").FindControl("txtEmployeeComments")).Text

Try this function (below) to do a recursive search for the ID. Most probably the System.NullReferenceException: Object reference not set to an instance of an object error is because the script did not find the text box so the control did not have a .Textproperty. NB: root would be the id of an asp.net placeholder object or an asp.net panel, etc. that contains the text box you are looking for. You should test for null returns before attempting to use the control.
public Control FindControlRecursive(Control root, string id)
{
if (root.ID == id) {
return root;
}
Control c = default(Control);
foreach ( c in root.Controls) {
Control t = FindControlRecursive(c, id);
if ((t != null)) {
return t;
}
}
return null;
}

AFAIK, ((TextBox)Page.Master.FindControl("x")).Text should work

Related

c# asp.net master page get a href and set visible to false

I have an a href link in my user.master page, but I'm unable to find that control in my user.master.cs. How do I do so? I tried using master and find control, but it says object reference is not instance to an object or it does not work. Please help, thanks.
user.master
Upgrade
user.master.cs
(first try)
var masterPage = Master;
if (masterPage != null)
{
masterPage.FindControl("showUpgradeLink").Visible = true;
}
(second try)
this.Master.FindControl("showUpgradeLink").Visible = false;
Did you put runat="server" on the a tag?
For example:
<a href="ViewPremiumPlans.aspx" id="showUpgradeLink" runat="server" class="btn-light btn-sm" >Upgrade</a>
You need to add runat="server" without that it is not a server control.
Upgrade
You then access it in the master (user.master.cs) page directly
showUpgradeLink.visible = false;
If you want to expose it to child pages add a public property to user.master.cs
public HtmlGenericControl UpgradeLink { get { return showUpgradeLink; } };
In your child aspx pages where you want to access the control/property add:
<%# MasterType virtualpath="~/Path/To/user.master" %>
Then in the child .cs pages you can use:
Page.Master.UpgradeLink.visible = false;

changing css in user control id

I'm trying to target the ID of an anchor within a user control named myMenu. The user control is on a master page. So, I'm trying to add a class of "active" from one of the content pages so it will highlight the link for that particular page. Right now I have:
if (Master != null)
{
var sitenav = (UserControl)Master.FindControl(id: "myMenu");
if (sitenav != null)
{
var navlink = sitenav.Parent;
}
}
I'm still trying to figure out the logic here and can't find anything that has that info. I know I'd do the htmlanchor as the type?
html in user control:
<li><a runat="server" ID="linka" href="#">Link A</a></li>
<li><a runat="server" ID="linkb" href="#">Link B</a></li>
<li><a runat="server" ID="linkc" href="#">Link C</a></li>
<li><a runat="server" ID="linkd" href="#">Link D</a></li>
MasterPage.cs:
... class MasterClass ...
public void performAction(bool toggle){
if (toggle){
myId.class += "active"; //something like that
}
}
ContentPage.cs
(MasterClass)performAction(true);
This is how you can access a master page function and get it to do something on the master page elements.
To add a css class from code behind, I'd refer you to this answer which is both elegant and complete.
Caspar Kleijne's answer
So your complete solution would be:
From within the Page you can cast the Master page to a specific type (the type of your own Master that exposes the desired functionality), using as to side step any exceptions on type mismatches:
Content Page:
var master = Master as MyMasterPage;
if (master != null)
{
master.AddClass("active");
}
In the above code, if Master is not of type MyMasterPage then master will be null and no method call will be attempted; otherwise it will be called as expected.
MasterPage
public void AddClass(string classname ){
// add a class
myMenu.CssClass = String.Join(" ", myMenu
.CssClass
.Split(' ')
.Except(new string[]{"",classname})
.Concat(new string[]{classname})
.ToArray()
);
}

Is there an ASP.NET databindable control (like Repeater), which only expects a single item?

I'm trying display lots of properties from a business object on a Web Form. I could of course, create loads of labels and assign all the values in code-behind, but I feel there must be a less verbose way.
What I want is something like an asp:Panel but where you can specify a datasource. It doesn't seem like Panels support any kind of databinding.
What I'd like is something like this
// C#
panel.DataSource = theCompany;
panel.DataBind();
Then:
// ASPX
<asp:Panel runat="server">
Name: <%# Eval("Name") %>
Phone: <%# Eval("Phone") %>
...
</asp:Panel>
..but I can't find anything which will allow me to work in this way.
I thought I might be able to use asp:FormView but this just gives the error "Data source is an invalid type. It must be either an IListSource, IEnumerable, or IDataSource."
A caveat is that I do not want to call a global DataBind() (this has caused us no-end of problems in the past) - I would like the databind to be constrained to a particular part of the page.
It seems you can do this using a Panel, but you have to assign your business object to a page property first, as there's no way to set the business object as a "DataSource" for the panel (as you would for a Repeater control, for instance).
Once the object is assigned as a page property, you can then use the following syntax in the .aspx to access the properties of that object, without needing to manually assign each item to control values in code behind:
<%# Company.Name %>
You don't need to databind (although you can). What you need is a simple expression evaluator. Add a property to your code behind like this
public string Test { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
Test = "<script>alert('test');</script>";
}
Then use it to render code directly to the page like this
The value: <%: Test %>
Note that the <%: syntax escapes the input. If you wish to NOT escape the input then you can use <%= syntax. Note that you don't need to have a string object you can access any properties you like for example
The value lenght: <%: Test.Length %>
Use The below:
<asp:DetailsView runat="server">
Name: <%# Eval("Name") %>
Phone: <%# Eval("Phone") %>
</asp:DetailsView>
Use DetailsView. You can add it from the Toolbox. It's for Single Row Data Presentation.
<asp:DetailsView runat="server">
Name: <%# Eval("Name") %>
Phone: <%# Eval("Phone") %>
</asp:DetailsView>
Why not using DetailsView. Its perfect for what you want. Showing single row of data only and that too in two column form.
I suggest using a standard Repeater, databound with an array containing a single item.
Repeater.DataSource = new [] { theCompany };
Repeater.DataBind();
Advantage over databinding to a Panel: you can still use the ItemType attribute, and have access to the nice strongly typed Item object and don't have to go about using Eval, i.e.:
<asp:Repeater runat="server" Id="Repeater" ItemType="CompanyViewModel">
<ItemTemplate>
Name: <%# Item.Name %>
Phone: <%# Item.Phone %>
</ItemTemplate>
</asp:Repeater>
(Replace "CompanyViewModel" with the Type of your: "theCompany".)
You can also try experimenting with DetailsView, but it's not as malleable as a Repeater.
Create your own user control that shows the properties of the objects. You can use reflection to read property names and values and display in control.
Create a property for your object in your user control. Inside user control code behind write function Show() with below code.
//Build html strin from all propeties
PropertyInfo[] properties = yourObject.GetType().GetProperties();
string lbl = "<label>{0}</label>";
string value= "<span>{0}</span>";
string tab ="\t";
StringBuilder sb = new StringBuilder();
foreach (PropertyInfo pi in properties)
{
var label = string.Format(lbl,pi.Name);
var val = string.Format(value, pi.GetValue(yourObject, null))
sb.Append(label+tab+val);
sb.Append("<br/>")
}
Response.Write(sb.ToString());
Now in your pager add that control and sets its object property in code behind like
myControl.MyObject = yourObject;
myControl.Show();
NickG's answer will work... however consider two scenarios.
If your business object is ever null, the page will crash with an "Object Reference" error. This can be avoided with a cumbersome looking
<% if(MyObject != null) { %><%= MyObject.Prop %><% } %>
... but doing that every time makes for messy code.
If your page uses PostBack processing via UpdatePanel, the business object will have to be reloaded to the property every time the Page lifecycle runs... even if that portion of the page isn't being redrawn. This is because IIS will resolve all the <%= MyObject.Prop %> references regardless, causing wasted CPU cycles and probably wasted database calls if your object is coming from a database.
For these reasons I always use a Repeater control, which is lightweight, supports ViewState, can easily be assigned a one item list, and avoids the aforementioned issues. Here's an example using the HttpContext.Current.Request object as a "business object".
<asp:Repeater ID="rptTest" runat="server">
<ItemTemplate>
Request.URL = <%# Eval("Url") %>
</ItemTemplate>
</asp:Repeater>
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
var objTest = Request; //Using the Request object as a test business object
rptTest.DataSource = new List<System.Web.HttpRequest>() { objTest };
rptTest.DataBind();
}
}
To make this work we can customize ASP.NET Panel by inheriting it and using Custom Server control for ASP.NET
Use Below Code to modify the ASP.NET Panel in an ASP.NET Custom Server Control Project:
[DefaultProperty("Text")]
[ToolboxData("<{0}:CustomPanel runat=server></{0}:CustomPanel>")]
public class CustomPanel : Panel
{
[Bindable(true)]
public object MyDataSource
{
get;
set;
}
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
public StringBuilder Text
{
get;
set;
}
public void MyDataBind()
{
Text = new StringBuilder();
foreach (PropertyInfo p in MyDataSource.GetType().GetProperties())
{
Text.Append(string.Format("<b>{0}</b>", p.Name));
Text.Append(":");
if (p.GetIndexParameters() == null || p.GetIndexParameters().Length == 0)
Text.Append(p.GetValue(MyDataSource, null));
Text.Append("<br />");
}
}
protected override void RenderContents(HtmlTextWriter output)
{
output.Write(Text);
}
}
Then add this control's reference and toolbox item to your ASP.NET page:
<cc2:CustomPanel ID="MyCustomPanel" runat="server">
</cc2:CustomPanel>
Use the control as shown below:
MyCustomPanel.MyDataSource = theCompany;
MyCustomPanel.MyDataBind();

ASP.Net WebForms LinkButton click, open new tab, passing id through hidden html input variable

I have an aspx webforms page with a repeater built through a user control. Each repeater item has a link button. What I want to happen is that when the LinkButton (in the repeater on page A's user control) is clicked, the url is opened in a new tab, and a hidden id next to that LinkButton is passed (according web development best practices for security if possible) to the aspx page (page B) in the new tab. Both pages A and page B are in the same application.The intent of what I described above is so that the user can easily return to their search results after returning from the URL opened by clicking on the LinkButton.I am open to ideas on how to do this that are closer to standard best-practice methods.
So far, I have tried:
1) cross-page posting – this worked for passing the id, but not for opening in a new tab.
2) Setting the PostBackUrl to page B's url, setting the Page.Form.Target="_blank" with OnClientClick calling javascript to set the hidden id from the user control to the value of an html hidden input on page B and also.
3) I also tried using window.open("page B url", "_newtab") in OnClientClick.
a) So far, the only method that worked correctly was the 2nd one from the 3 different methods above. However, after page B is loaded in the new tab, I don't know how to reset page A's Page.Form.Target back to what it was previously before setting it to "_blank"
b) The methods that I have tried, to no avail, to reset the Page.Form.Target have been:
1) Resetting the target in page A's Page_Load where IsPostBack == true --> that caused Page B to load with the same content as Page A.
2) Resetting the target in page A's user control's Page_Load --> same result as method 1
3) Resetting the target in page A’s user control’s LinkButton’s OnUnLoad in page A's user control --> same result as method 1
4) Resetting the target in javascript through the LinkButton’s OnClientClick --> didn’t work
5) Resetting the target in page B's Page_Load using a public variable from page A containing a reference to page A's form (similar to what can be done through cross-page posting) --> didn’t work.
What I am thinking about trying next is:
1) Wrapping another user control on page A to display page B's content, in an asp Panel (Panel B)
2) Put page B’s content into the new user control page
3) Wrapping the search results content on page A in an asp Panel (Panel A).
4) When the LinkButton in the repeater on the new user control is clicked, the search results content in Panel A will be hidden, and Panel B will be shown.
5) When the user wants to return to the search results, they will click on a ‘Return to Search’ LinkButton in Panel B’s content, and then Panel B will be hidden, then content of Panel B will be cleared, and Panel A will be shown again.
I'm not yet sure if that will work though. It doesn't seem like this should be that difficult. It is a straight-forward concept, and I would think is a fairly common situation in web development.
I feel like Wiley Coyote trying to catch the Road Runner because I come up with elaborate intelligent, thought-out plans that all completely fail. I am now holding up a little sign that says, "Help!
I had the same issue resolve by the following code you just try this in ur HTML page for a button in GRIDVIEW:
<asp:LinkButton ID="LinkButton1" runat="server" Text="View" CommandArgument='<%# Bind("ref") %>'
OnClick="LinkButton1_Click" OnClientClick="document.forms[0].target ='_blank';">View</asp:LinkButton>***
I actually got this figured out.
I figured it out through a combination of the marked-answer on this post, How to Open new tab when we click on LinkButton, and the marked-answer on this post, Is it possible add click event to hyperlink?.
My Repeater ItemTemplate in the user control's repeater looks similar to this:
<asp:HiddenField ID="hfId" runat="server"
Value='<%# Eval("Id") %>'/>
<asp:HyperLink ID="myLink" runat="server"
Text='<%# Eval("Name") %>'
NavigateUrl="/myUrl.aspx"
Target="_blank" />
<asp:Button ID="btnSubmit" runat="server"
Text="Submit"
OnClick="BtnClick"
Style="display: none;" />
This is my code in the ItemDataBound of the repeater:
protected void RptrItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
var myId = "";
var myNameLink = e.Item.FindControl("myLink") as HyperLink;
if (myNameLink != null)
{
var submitButton = e.Item.FindControl("btnSubmit") as Button;
if (submitButton != null)
{
var submitButtonClientId = submitButton.ClientID;
myNameLink.Attributes.Add("onclick", "onNameClick('" + submitButtonClientId + "')");
}
}
}
}//end RptrItemDataBound
The javascript code:
<script type="text/javascript">
function nameClick(buttonId)
{
document.getElementById(buttonId).click();
}
</script>
And here is the BtnClick C# code:
protected void BtnClick(object sender, EventArgs e)
{
var btnSelect = sender as Button;
if (btnSelect == null)
{
return;
}
var myListItem = (RepeaterItem)btnSelect.DataItemContainer;
if (myListItem != null)
{
var hfId = myListItem.FindControl("hfId") as HiddenField;
if (hfId != null)
{
var intId = int.Parse(hfId.Value);
Session["selectedId"] = intId;
}//end if (hfId != null)
}//end if (myListItem != null)
}//end btnClick

Adding an ASP.NET Web User Control to a Control Dynamically

I have a simple ASP.NET Web User Control. It looks like this:
<%# Control Language="C#" AutoEventWireup="true"
CodeBehind="NewsArticle.ascx.cs"
Inherits="Website.Controls.NewsArticle" %>
<div>
<asp:Literal ID="ltlBody" runat="server" />
</div>
My code behind looks like this:
namespace Website.Controls
{
public partial class NewsArticle : System.Web.UI.UserControl
{
public String bodyText
{
//get { return ltlBody.Text; }
set { ltlBody.Text = value; }
}
}
}
On a .aspx page I have <asp:Panel ID="pNews" runat="server" />
In the code behind I have:
foreach (vwNews news in newsQuery)
{
NewsArticle article = new NewsArticle();
article.bodyText = news.Body;
pNews.Controls.Add(article);
}
Every time I run this code the newsQuery is populated correctly and I get to the line
aticle.bodyText = news.Body; and then I received the error article.bodyText threw an exception of type 'System.NullReferenceException'
I am not sure what is causing this error message or how to fix it. I would think that there should not be an issue. I tried creating a constructor for my Web User Control so that it would give default values to my properties but that didn't work. Any idea how to make this work? It doesn't seem like it should be that
To load a control programatically you need to use the Page.LoadControl() method. See this MSDN article
You have a typo within the code you've written. 'aticle' instead of 'article'.

Categories