Accessing text boxes in a web control on a master page - asp.net

I need to access multiple textboxes on a master page. The textboxes are declared in a separate web control and it won't let me call the names of the textboxes so I can populate them with data. I have multiple textboxes like I said, but for example, when I try to write to txtName it will not let me even though when I click on the Design View it says it is there.
Can anybody help me out?

Expose the text boxes inside the web control as properties.
In webcontrol.ascx
<asp:TextBox runat="server" id="txtName" />
In webcontrol.ascx.cs
public virtual TextBox TxtName { get {return txtName;} //note capitalization
Then do the same thing in the master page to expose the web control.
In masterpage.master
<uc1:MyWebControl runat="server" id="MyWebControl1" />
In mastermage.master.cs
public virtual MyWebControl myWebControl{get {return myWebControl1;}}
Then make your master page strongly typed from the content page by adding a MasterType directive.
In default.aspx
<%# MasterType TypeName="MyMasterPageClass" />
Then you can access it from your content page code behind. In default.aspx.cs
Master.myWebControl.TxtName.Text="Hello, world!";
The reason it's necessary to do this is that controls declared on .aspx, .ascx, and .master pages are protected instead of public and there's no way (as of right now) to change them that I'm aware of. So we can use properties to expose these controls as public.

Related

How can I access an object inside of an asp:LoginView

I have a LoginView on a site master page that displays the username of the logged-in user. I modifies it to make the username a link to that user's settings, using a LinkButton.
I need to be able to conditionally enable or disable the LinkButton from within Page_Load. How do I get a reference to the LinkButton?
The LinkButton doesn't appear in the designer.cs file, but the LoginView does. I have tried looking at its controls property in the debugger and also tried using FindControl(LinkButton's ID) but that returns null.
--Jacob
You can't use the LogIn "as is", you have to create a LayoutTemplate inside the control.
<asp:Login ID="LoginUser" runat="server">
<%--the LayoutTemplate must include controls (with Text property)
with ID values UserName and Password--%>
<LayoutTemplate>
Your stuff here. Textboxes for user name and password, etc...
</LayoutTemplate>
</asp:Login>
Then you can find a control by
Label myErrorLabel = (Label)LoginUser.FindControl("logInErrorDetails");
Make sure that LinkButton is Asp.Net server control with "runat="server" attribute. If it is a server control then it should appear in your designer.cs file. Once it appeared in designer.cs file, you can access that control by its name or using FindControl method.
Some times Visual Studio IDE creates problem and it does not update desinger.cs file. Try to switch between designer view, mark up view and code view. It will update designer.cs file if the markup is correct.

Acess a control of a user control in a content page of a master page

I have user control (ascx) in a Master Page.
Then I have a content page (aspx) that uses that Master Page.
Now, in the content page, I want to access a hiddenfield control that is placed in the user control.
How do I do that?
I tried the following but it returns null.
Master.FindControl("MyHiddenField")
Master.FindControl("MyUserControl1_MyHiddenField")
Thanks
In your content page (.aspx) place this code. It will make the Master Page strongly typed for the content page.
<%-- The Page directive goes here --%>
<%# MasterType TypeName="MyMasterClassName" %>
<%-- Rest of your code below.. --%>
In the Master Page code behind, place this code
public UserControlTypeName MyUserControl1
{
get {return myUserControl1; }
set {}
}
This makes the User Control instance public. You'll need to rename the ID of the user control to myUserControl1.
Then in your UserControlTypeName (or whatever the name of your class is for your User Control) you can make the inner controls accessible in the same manner we did on the master page.
public HiddenField
{
get {return myHiddenField;}
set {}
}
Obviously, rename the ID for MyHiddenField to myHiddenField to avoid a conflict.
Finally, this allows your content to access the controls within the user control that are on the master page through strong typing.
public void Page_Load(object sender, EventArgs e)
{
Master.MyUserControl1.MyHiddenField.Value="Hello, world!";
}
For further reference, see Working with ASP.NET Master Pages programmatically on MSDN.
If Microsoft Is Listening...
If for some reason a Microsoft ASP.NET developer is reading this answer, please consider doing something like this:
<asp:Button runat="server" scope="public" id="MyButton1 />
That would make it much easier than having to create wrapper properties to make inner controls publicly accessible.

ASP.NET #Register vs. #Reference

I'm working with referencing user controls on my ASPX page and I'm wondering what the difference is between these two page directives.
#Reference
#Register
#Register is primarily used for registering tag prefixes to declaratively use controls within a page.
<%# Register tagprefix="my" namespace="MyNamespace" %>
<my:CustomControl runat=server />
#Reference is primarily used to refer to a page or user control (by file name or virtual path) to programatically refer to members of the page or control.
<%# Reference Control="MyControl.ascx" %>
<% MyControl ctrl = (MyControl) Page.LoadControl("MyControl.ascx");
ctrl.CustomProperty = "..."; //REFERENCE directive is needed to access property
%>
#Register is the more commonly used directive. You use this when you want to use a user control in your aspx or ascx page declaratively. #Register associates the control with a specific prefix and you can then use it in your markup.
#Reference only tells ASP.NET to compile the other control when your aspx or ascx page is compiled. That makes sure it is available at run-time and can be added to your control hierarchy programmatically. This is less common since dynamically changing user controls at runtime is not comon.
Here's a good blog post about it.
http://weblogs.asp.net/johnkatsiotis/archive/2008/08/13/the-reference-directive.aspx

Form tag on ASP.net page

I have a web application that has a page that loads the content from the database. I want to be able to put a form in the dynamic content, but .net doesn't let the inside form perform it's action. Is there a way to allow this or some other way I can get a form on a dynamic content page?
--EDIT--
I think I need to clarify something. This is an aspx page that loads content from the database. As far as I know, the text I pull from the db and stick in the Label is never compiled or processed by the .net wp, thus I can't use the code behind to fix this issue.
This is a common problem, when you want to have a non-postback form to a 3rd party site (like a PayPal button, for example).
The problem occurs because HTML doesn't let you have form within a form, and most ASP.NET pages have a <form runat="server" /> "high up" in the HTML (or in the Master page).
My favorite solution is to hide the "high up" form tag, while still showing all of the content. Then you can feel free to dump any tags you want in the body. If you do this dynamically you can choose on a page-by-page basis which pages have custom forms.
I created a class called GhostForm.cs to handle this. You can read all about it here:
http://jerschneid.blogspot.com/2007/03/hide-form-tag-but-leave-content.html
There can only be one form on the page (the asp form); you have to use that form somehow.
To clarify, there can only be one form processed.
Not with webforms, no. You have to work within the one, full page form by using an event handler connected to a Button to LinkButton. Fortunately, it's pretty easy to do:
foo.aspx:
...
<asp:TextBox id="txtFoo" runat="server" />
<asp:Button id="btnFoo" runat="server" onclick="btnFoo_Click />
...
foo.aspx.cs:
...
protected void btnFoo_Click(object sender, EventArgs e)
{
string s = txtFoo.Text;
// do something with s
}
...
Dino Esposito has an article from MSDN magazine that covers handling multiple forms or "simulating" sub forms in ASP.Net that might just answer all your questions.
http://msdn.microsoft.com/en-us/magazine/cc164151.aspx
Any work around would be hacky and very ugly. By design asp.net uses a form tag to post and get data. This is why they call it a Web Forms Application. Html does not allow nested forms. What you want to do is use a WebRequest in your code behind.
If you are trying something like a paypal button you could simply use something like this.
Markup:
<div id="PayPalButtonContainer" runat="server"></div>
Code Behind:
public static string GetPayPalButtonMarkup()
{
const string markup = #"https://www.paypal.com/cgi-bin/webscr
?cmd=_xclick&business={0}
&item_name=Widget
&amount={1}
&currency_code=USD";
return markup;
}
PayPalButtonContainer.InnerHtml = string.format(GetPayPalButtonMarkup,"YOUR PAYPAL USER NAME", "YOUR PRICE VALUE");
you either have to deal with the postback by adding a server side click event handler to what you want to be the "sub forms" submit button (this is how web formas deals with multiple submit type buutons on the same page) or do soemthing clever with AJAX if you dont want a full post back
I've run across this issue before. One workaround that I have done is to place my code that I want my action to be done upon inside of an asp:Panel. With the panel you can set the attribute of "DefaultButton" to a button inside of the panel, and clicking the button (or pressing "enter") will fire that button's click event. I've found this quite handy when wanting to submit a "form" by pressing enter when I have a master page that contains the only allowable asp:Form.
Hope this helps.
When I first came across this problem, I found the simplest solution for me was to simple COPY and PASTE the Master page and give it a slightly different name, something like:
SiteNameMasterPage 'Default page with FORM tag
SiteNameMasterPageNF 'No Form tag
And then depending on wether I wanted a FORM tag or or not, simply change the masterpage link at the top of my CONTENT-PAGES, like this
<%# Page Title="" Language="VB" MasterPageFile="~/SiteName.master" %>
<%# MasterType VirtualPath="~/SiteName.master" %>
<!-- This masterpage has the default FORM tag -->
or
<%# Page Title="" Language="VB" MasterPageFile="~/SiteNameNF.master" %>
<%# MasterType VirtualPath="~/SiteNameNF.master" %>
<!-- This masterpage does NOT have the default FORM tag -->
and then in the content page, wherever I want to place my form I can include the <form> tag

FormView on a Master Page can't see databound controls through ContentPlaceHolder boundary

I have a number of similarly structured FormViews. In an effort to avoid duplicate markup, I've created a master page that contains the FormView, and placed a ContentPlaceHolder inside the FormView. The specific databound controls - which are the only thing that change from page to page - are then on the page that uses that master page.
So I have a master page that looks something like this:
<%# master ... %>
...
<form runat=server>
...
<asp:formview runat="server" ... >
<edititemtemplate>
... Lots of common markup ...
<asp:contentplaceholder id='FormRows' runat='server' />
... Lots more common markup ...
</edititemtemplate>
</asp:formview>
...
</form>
and a page using that master page that looks something like this:
<%# page masterpagefile="Form.Master" ... %>
<asp:content contentplaceholderid="FormRows" runat="server" >
...
<p>
Field One:
<asp:textbox runat=server text='<%#Bind("Field1")%>' id='Field1' />
</p>
<p>
Field Two:
<asp:textbox runat=server text='<%#Bind("Field2")%>' id='Field2' />
</p>
...
</asp:content>
With an existing record, the FormView sees through to the databound controls (Field1, etc) and populates them with the correct data. But when inserting or updating, it doesn't see them, and they're not included in the insert or update. In the FormView_ItemInserting event, e.Values is empty; likewise in the FormView_ItemUpdating event, e.NewValues is empty.
So:
Is there a way to provoke the FormView on the master page to see through to the databound controls inside the ContentPlaceholder?
Failing that, is there a straightforward way of identifying controls that are databound with <%#Bind(...)%> so that I can add them manually to the values bag?
There are a couple of things that come to mind why this setup will not work and may lead to more code than markup.
If you have a datasource defined in the master page it will not handle the different data bound controls from each page without adding more logic to the master page to change the query etc.
All form views will be coupled together increasing the complexity of changes down the road
I would go with separate pages for each FormView reducing the complexity of code, debugging and the ability to change
Just my two cents
I think this will prove difficult, if not possible; in fact I'm surprised that the databinding works at all!
You may want to try a different method of encapsulating your FormView control.
You could try placing the FormView control in an .ascx control with a PlaceHolder where you now have the ContentPlaceHolder.
Then on each ASPX page, you could have a mirror ASCX page that contains the filler for the placeholder. You could give them the same names (Page1.aspx uses Page1.ascx) or set up a naming convention like Page1-Content.ascx, so that your FormView ascx would figure out what it's filler control is named, use Page.LoadControl() to load the control by path, and plug that content in during the Init phase.
Now, your content controls have the advantage of being able to have public properties, so you could bind to those public properties, and have the properties shuttle the data to and from the appropriate server controls in the filler .ascx file.
Unfortunately it's double the files (because of the ASPX and ASCX required for each page) but fairly work-unintensive compared to the alternative (duplicating all that code)
Of course, you haven't told us what all your common markup is, but your common markup could go into a CommonMarkupHeader.ascx and CommonMarkupFooter.ascx as well and included on each page's unique FormView.
Where do you have server form tag? May be in content place holder insted of master page, so your values not send to server page after submit
You might be able to do something like this...
Define an interface for your "data pages" that has a method signature that returns a bindable data source..
public interface IFormViewChild {
IEnumerable GetFormData();
}
Then you can have your "data pages" implement that interface...
public class ChildDataPage : Page, IDataPage {
public IEnumerable GetFormData() {
// code to return stuff here
}
}
Finally, in your masterpage's Load() event...
if (Page is IFormViewChild) {
myFormViewControl.DataSource = ((IFormViewChild)Page).GetFormData();
myFormViewControl.DataBind();
}
Please keep in mind that this is all psudo code typed directly into this web form editor.. so it's probably wrong. But it might not be :)
Here's a provisional solution - not elegant, but it works. In the code-behind for Form.Master I have something along these lines:
Private Sub FormView1_ItemInserting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.FormViewInsertEventArgs) Handles FormView1.ItemInserting
ManuallyAddValues(e.Values)
End Sub
Private Sub FormView1_ItemUpdating(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.FormViewUpdateEventArgs) Handles FormView1.ItemUpdating
ManuallyAddValues(e.NewValues)
End Sub
Private Sub ManuallyAddValues(ByRef Values As IOrderedDictionary)
For Each Field As Core.Field In FormView1.DataSourceControl.IncludedFields
If Values(Field.Name) Is Nothing Then
Dim DataboundControl As Control = FormView1.FindControl("FormRows").FindControl(Field.Name)
Values.Add(Field.Name, GetValue(DataboundControl))
End If
Next
End Sub
This isn't so elegant because
I have to know the names of all databound controls
This relies on the assumption that the ID of each control matches the fieldname
The 'GetValue' function (not included here) is a clumsy solution: it checks for various types (textbox, dropdownlist, checkbox, etc.) and gets the string value from the appropriate property (textbox.text, dropdownlist.selectedvalue, checkbox.checked, etc.).
I'd still love to at least have a way of knowing what's bound with the '<%#Bind("Foo")%>' syntax and getting that information directly.

Resources