How to do Code Behind for a User Control File - asp.net

I have a dynamic menu that shows select items based on flags in my database. Currently I have the menu on my .aspx page and the code behind on my .aspx.vb page. I'm adding in alot more pages, so I'm trying to seperate the menu using a User Control. However, I'm not sure how to reference the code behind for the .ascx page.
Current code:
<ul>
<li id="form1" runat="server"><a title="a" href="a.aspx" target="_blank">A Form</a></li>
<li id="form2" runat="server"><a title="b" href="b.aspx" target="_blank">B Form</a></li>
</ul>
Code Behind:
Private Sub Customer_LoadData()
'DECLARE LOCAL VARIABLES
Dim objContract As Contract = Nothing
Dim objContractDL As New ContractDL
'RETRIEVE THE CUSTOMER'S CONTRACT INFORMATION
If objContractDL.Read(objContract, zintCustomerID) Then
Call DisplayCustomer(objContract)
Call DisplayForms(objContract)
End If
End Sub
Private Sub DisplayForms( _
ByVal objContract As Contract _
)
If (objContract.fieldFedLoansFlag = "0") Then
authform1.Visible = False
Else
authform1.Visible = True
End If
End Sub
I've never seen a .ascx.vb page before, so i don't think that is the solution.

From the comments above you are using the Page Directive and with Custom Controls you should be using the Control Directive
<%# Control Language="vb" AutoEventWireup="false" CodeFile="menu2.ascx.vb"
Inherits="menu2" %>
From the Microsoft site the difference between a user control and a page
A user controls differs from an ASP.NET Web page in these ways:
The file name extension for the user control is .ascx.
Instead of an # Page directive, the user control contains an # Control directive that defines configuration and other properties.
User controls cannot run as stand-alone files. Instead, you must add them to ASP.NET pages, as you would any control.
The user control does not have html, body, or form elements in it. These elements must be in the hosting page.

Related

* is not declared. It may be inaccessible due to its protection level

I've got a problem with one of my web forms pages.
this is how it started.
I needed to completely revamp a page, I renamed the old pages default.aspx.vb.old and default.aspx.old and created brand new default.aspx and default.aspx.vb pages
every time I add a control to the aspx page and try and reference it in the code behind, I get the error 'lblError' is not declared. It may be inaccessible due to its protection level
Page decalaration
<%# Page Title="" Language="VB" MasterPageFile="~/_Masters/Principle.master" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="Magazine_Default" EnableViewState="false" %>
Label control in Default.aspx
<asp:Label ID="lblError" runat="server" CssClass="cError" Visible="false" />
Default.aspx.vb Code Behind
Partial Class Magazine_Default
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
lblError.Text = "There was a problem retrieving the magazines, please try again later"
End Sub
End Class
the page works, but visual studio will not build because it insists there is an error.
I thought it might be something up with my visual studio, like cache or something, so i nuked any temp files relating to the project.
and this morning a colleague did a git pull and has the same problem, errors are there, refuses to build but the page works.
The project itself is a website project, so there's no designer files where I can change the access modifier of the control.
I have also tried creating a new file, using the web form scaffolding that visual studio provides through add->web form, which has all the correct page directives in the .aspx and correct class declarations in the .aspx.vb, and it still does it.
There is also no red squiggly line under lblError.Text
When I create a new page in the different folder, it doesn't happen.
As you renamed old default.aspx page, you need to rename its class too. Generally when you rename aspx page, it will not rename class name automatically. So you need to do that manually.
So for default.aspx page,
Inherits="Magazine_Default_Old"
And for default.aspx.vb page,
Partial Class Magazine_Default_Old
This will solve issue.

Invalid viewstate error when posting back to same page

I'm having some issues with an Invalid Viewstate error and I can understand why it's happening but I don't know how to fix it.
I have a page which is similar to this /story/?id=123 but I'm using a different page to Server.Transfer to this page.
So I've set up /info to Server.TransferRequest("/story/?id=123") and it works fine until the page does a postback to itself.
We have a login form on this page which simply reloads the page but when it does it seems to add /?id=123 onto the end of the URL so it ends up like this /info/?id=123 thus causing an Invalid Viewstate error.
I've already tried adding EnableViewStateMac="false" - this fixes the error but it doesn't log the user in as expected so it does not give the required result.
So my questions are:
Is there a better way to redirect to my page other than Server.TransferRequest but still keeping the nice URL? - I don't want to Response.Redirect if I can avoid it.
If not, is there an easy way to fix this error that doesn't require me adding EnableViewStateMac="false"?
http://support.microsoft.com/kb/316920
I believe that article will explain why you are having the problem and it gives a solution to fix it.
I know you don't want to use Response.Redirect, but I think that would also solve the problem.
PRB: "View State Is Invalid" Error Message When You Use Server.Transfer
This article was previously published under Q316920
Retired KB Content Disclaimer
This article was written about products for which Microsoft no longer
offers support. Therefore, this article is offered "as is" and will no
longer be updated.
SYMPTOMS
When you use HttpServerUtility.Transfer("page name", true), you
receive the following error message:
The View State is invalid for this page and might be corrupted
CAUSE
This problem occurs because the EnableViewStateMac attribute of the
<pages> element is set to true by default. When this attribute is
set to true, ASP.NET runs a message authentication check (MAC) on the
view state of the page when the page is posted back from the client.
This check determines if the view state of the page was modified on
the client. For security purposes, it is recommended that you keep
this attribute set to true.
When you call the Server.Transfer method and set the second
parameter to true, you preserve the QueryString and the Form
collections. One of the form fields is the hidden __VIEWSTATE form
field, which holds the view state for the page. The view state message
authentication check fails because the message authentication check
only checks each page. Therefore, the view state from the page that
calls Server.Transfer is not valid on the destination page.
View state is page scoped and is valid for that page only. View state
should not be transferred across pages.
RESOLUTION
To resolve this problem, use one of the following methods.
Resolution 1
Transfer values between pages to pass your server control values to
the other pages. For more information, refer to the following MSDN
documentation: Passing Server Control Values Between
Pages
This requires that you create public properties for each property of a
control that you want to access from the destination page.
If you have many controls, and if you want to access the properties of
these controls from another page, you can also declare those controls
as public variables. For example:
Page1.aspx
Public Class Page1
Public WithEvents TextBox1 As System.Web.UI.WebControls.TextBox
'Insert your code here.
End Class
Page2.aspx
Dim sourcePage As Page1
sourcePage = CType(Context.Handler, WebForm1)
Response.Write(sourcePage.TextBox1.Text)
Resolution 2
Do not pass the second parameter (which is false by default) when
you call Server.Transfer. For example:
Server.Transfer("<page name>")
This code does not send the QueryString and the Form fields to the
page that is called. When no data is transferred, ASP.NET does not run
the message authentication check.
MORE INFORMATION
Steps to Reproduce the Behavior
Create an .aspx page named WebForm1.aspx that transfers execution to another page. Add the following code to WebForm1.aspx:
<%# Page language="vb" AutoEventWireup="true" %>
<html>
<body>
<form id="WebForm1" method="post" runat="server">
<asp:TextBox id="txtName" runat="server">Your Name</asp:TextBox><br>
<asp:Button id="Button1" runat="server" Text="Submit" OnClick="Button1_Click"></asp:Button>
</form>
</body>
</html>
<script runat=server>
Sub Button1_Click(sender As Object, e As System.EventArgs)
Server.Transfer("WebForm2.aspx",true)
End Sub
</script>
Create another .aspx page named WebForm2.aspx, and then add the following code:
<%# Page language="vb" AutoEventWireup="true" %>
<html>
<body>
<form id="WebForm2" method="post" runat="server">
<asp:Label id="lblName" runat="server" >Web Form 2</asp:Label>
</form>
</body>
</html>
<script runat=server>
Sub Page_Load(sender As Object, e As EventArgs)
Dim thisPage As System.Web.UI.Page
Dim nameTextBox As TextBox
thisPage = CType(Context.Handler, System.Web.UI.Page)
nameTextBox = CType(thisPage.FindControl("txtName"), System.Web.UI.Control)
lblName.Text = "Your name is '" & nameTextBox.Text & "'."
End Sub
</script>
Open WebForm1.aspx in your browser, and then click Submit.

My custom server control is generated as System.Web.UI.UserControl in the designer file

I created a server control which consist only of fews buttons.
CWNavigation.vb
<ToolboxData("<{0}:CWNavigation runat=""server""></{0}:CWNavigation>")> _
<DefaultProperty("Id")> _
Public Class CWNavigation
Inherits WebControl
I then referenced it in my ASPX page. Take note that the control are in the same solution, same project located in Commun/Navigation/CWNavigation.vb.
<%# Register TagPrefix="NAV" TagName="CWNavigation" Src="~/Commun/Navigation/CWNavigation.vb" %>
I added it to the page.
<NAV:CWNavigation ID="CWNavigationService" runat="server" />
But the designer file along with the code-behind generate it as.
Protected WithEvents CWNavigationService As Global.System.Web.UI.UserControl
But this is wrong.. it must be CWNavigation. Is there anything ive done wrong ?
Thanks!
Since its a custom Server Control you should register it as an assembly. Something like this...
<%# Register Assembly="Control.Assembly.CWNavigation" TagPrefix="NAV" TagName="CWNavigation" Namespace="Namespace.Of.Control.Assembly" %>
Or add it to your ToolBox (Context Menu->Choose Items) and then drag and drop (which will have Visual Studio wire it up for you).

Dynamically place a user control based on Code Behind (VB.net)

I have a user control which is essentially a main menu.
I can place it into my MasterPage hard-coded, but I don't want that, I want to be able to dynamically place it with the code behind of the MasterPage.
<controls:mainMenu ID='MainMenu1' runat='server' />
So what I am looking to do is something like
if **condition is true ** _
response.write('<controls:mainMenu ID='MainMenu1' runat='server' />')
Of course, I know that won't work, but how would I place the control based on a condition in code behind on the master page?
I'm using VB by the way, not C#
You could do something like this -
Dim myControl As Control = CType(Page.LoadControl("yourcontrol.ascx"), Control)
if **condition is true ** _
Panel1.Controls.Add(myControl)
You'd need to add a Panel or PlaceHolder control to your page to hold your control.

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