Dynamic nested master pages, shared properties - asp.net

I have a base master page that specifies the main layout template of a website. It also handles some logic that changes tabs depending on the section, and also sets page meta information.
I'm dynamically loading nested master pages by looking at the querystring, loading up a record from the database, and setting the nested master page dynamically based on a value found in that record. I need to load dynamic nested master pages for layout and functional differences.
There is additional information in that record that I want to use in the base master page and in the dynamically loaded master page so I can avoid additional database calls.
Currently, I have set up a class that inherits MasterPage to act as the base class for the base master page. I have a shared (static) property that holds the object representing the database call that I want to share between the base master page and the nested, dynamically called master page.
It works, but it seems a little ugly. Are there any other better solutions?

You could always pass the record in the HttpContext.Items collection. Once it is in the Items collection it is available to every thing that can reach the HttpContext for the duration of the request.

Ok, I had to sleep on this one a bit, but I came up with a cleaner solution. I ended up using a base class for the page, instead of a base class for the master page. The base page sets the meta that I was going to set in the base master page.
Public Class PageBase
Inherits Page
Private _DocDetails As FolderDocument
Public Overridable ReadOnly Property DocDetails() As FolderDocument
Get
Return _DocDetails
End Get
End Property
Private Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack() Then
SetMeta()
End If
End Sub
Protected Sub SetMeta()
If DocDetails IsNot Nothing Then
Page.Title = DocDetails.MetaTitle
If DocDetails.MetaKeywords <> String.Empty Then
Dim metaKeywords As New HtmlMeta()
metaKeywords.Name = "Keywords"
metaKeywords.Content = DocDetails.MetaKeywords
Page.Header.Controls.Add(metaKeywords)
End If
If DocDetails.MetaDescription <> String.Empty Then
Dim metaDescription As New HtmlMeta()
metaDescription.Name = "Description"
metaDescription.Content = DocDetails.MetaDescription
Page.Header.Controls.Add(metaDescription)
End If
End If
End Sub
End Class
..And then the aspx page inherits this base page and dynamically sets the master page.
<%# Page Language="VB" Inherits="PageBase" %>
<script runat="server">
Private _DocDetails As FolderDocument
Public Overrides ReadOnly Property DocDetails() As FolderDocument
Get
Return _DocDetails
End Get
End Property
Protected Sub Page_PreInit(ByVal sender As Object, ByVal e As System.EventArgs)
_DocDetails = FolderDocuments.GetFolderDocument()
If _DocDetails IsNot Nothing Then
If _DocDetails.MasterPage <> "" Then
Me.MasterPageFile = String.Format("~/templates/{0}.master", _DocDetails.MasterPage)
End If
End If
End Sub
</script>
...and in the dynamically called master page I can reference the page's base class by casting:
Dim parentPage As PageBase = DirectCast(Page, PageBase)
Response.write(parentPage.DocDetails.Title)

Related

Anyway to modify a masterpage control from a contentpage update panel?

Here is what I came up with for a single-source popup modal for a web application.
I put a placeholder on the master page and the code below in a separate class. The class file receives the message and builds the modal html.
This works on full postback, but not when called from within an ajax update panel.
I know why. I just don’t know of any way around it. Any ideas?
Public Class Common
Inherits SiteMaster
Public Shared Sub showModalMsg(ByVal sMsg As String)
Dim lbl As New Label
lbl.Text = sMsg
'(for simplicity, the building of the div to make the modal is omitted)
Dim pageHandler = HttpContext.Current.CurrentHandler
If TypeOf pageHandler Is System.Web.UI.Page Then
Dim ph As PlaceHolder = DirectCast(pageHandler, System.Web.UI.Page).Master.FindControl("phModalDialog")
If ph IsNot Nothing Then
ph.Controls.Add(lbl)
End If
End If
End Class
Ok, here is what I did. I added an optional variable called 'container' that can be passed when calling the dialog within an update panel.
Public Shared Sub showModalMsg(ByVal sMsg As String,
Optional ByVal container As Control = Nothing)
I posted my full solution here:
How can I use a single modal across my web application and avoid repetative html on every page?

Property Value gets cleared on PostBack

I have to Get and Set the BackColur of Current Page. So user can use this property from any other page
And this is my code
Private _BackgroundColour As System.Drawing.Color
Public Property MenuBackColour() As System.Drawing.Color
Get
Return _BackgroundColour
End Get
Set(ByVal value As System.Drawing.Color)
_BackgroundColour = value
End Set
End Property
Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
Try
NavigationMenu.BackColor = MenuBackColour
Catch ex As Exception
End Try
End Sub
But the problem is Property value gets cleared on PostBack so I'm not able to get the BackColor value from other page
On post back only the input elements are posted.
So they are the same as before the post back, what they have before the post back, have and now. So actually you do not "get" this parameters on code behind, you only "set" them and on server controls with viewstate on, you can remember this parametres on post back - but you can not change them on client side and expect to read this change on server.
Here the workaround is. Either use the viewstate of the page to save some values and keep them on post back, ether use input hidden elements to have them on post back.
If your main purpose is to retain or share the backcolor of some control between different pages, there are many ways to do it in ASP.NET. You can keep the value in cookies or sessions, or cache.
As per request, if Property must be used, I create a Default.aspx as the following:
Public Class _Default
Inherits Page
Private Shared _BackgroundColour As System.Drawing.Color = Drawing.Color.Azure
Public Shared Property MenuBackColour() As System.Drawing.Color
Get
Return _BackgroundColour
End Get
Set(ByVal value As System.Drawing.Color)
_BackgroundColour = value
End Set
End Property
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
MenuBackColour = Drawing.Color.Red
Response.Redirect("Default1")
End Sub
End Class
It will automatically be redirected to Default1.aspx, where there is a Label control in that page. It will use _Default.MenuBackColour as the label's backcolor:
Public Class Default1
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Label1.BackColor = _Default.MenuBackColour
End Sub
End Class
Again, this approach is not recommended. If Default.aspx has never been run (at least once), MenuBackColour's value may not be what you think it is. I won't encourage people to retain any static variable or property in an .aspx page for sharing.
In web applications, variable values simply get erased. But it is very simple to persist these values. They may be persisted using the Viewstate object. Before the postback is invoked, the variable's value is saved in a viewstate object. In the recieving page, the viewstate's value may be retrieved back.
//Save the value in ViewState object before PostBack
ViewState("myColour")="Black";
//Retrive the value from ViewState after the PostBack
myColourProperty=ViewState("myColour").ToString();

Over ridding Methods in User control

Hi i have a user control that contains a button. I want to Over ride a custom function on click of that button like
Protected Sub btnUploadSpreadSheet_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnUploadSpreadSheet.Click
MyMethod()
End Sub
Public Overridable Sub MyMethod()
' this i want to over ride
End Sub
and in my page where i have added my control when i tried to over ride
Protected Overrides Sub MyMethod ()
End Sub
It is not finding that sub in the base class.
That's because the page is not a child of your UserControl(your page does not inherit from it) and this is the wrong approach anyway. Look up "Inheritance in Visual Basic": http://msdn.microsoft.com/en-us/library/5x4yd9d5%28v=vs.90%29.aspx
What you apparently want is to handle a custom UserControl's event in your page:
Your UserControl:
Class ExcelSheetUploader
Inherits UserControl
Public Event Uploaded(ctrl As ExcelSheetUploader)
Protected Sub btnUploadSpreadSheet_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnUploadSpreadSheet.Click
RaiseEvent Uploaded(Me)
End Sub
End Class
Now you can handle it in your page:
Protected Sub ExcelSheetUploader_Uploaded(ctrl As ExcelSheetUploader) Handles ExcelSheetUploader1.Uploaded
' Do something .... '
End Sub
MSDN: RaiseEvent
You cannot do this because your page is not extending the user control. Only in such a situation your implementation would be suitable
You can not directly override the methods or properties if some class
(e.g. Page) does not inherit You custom Class(Control). If you want to
do some functionality on some event on the page or button click then
create the public methods on the UserControl that raise some event or
execute some code.
Note - Must follow the page - life cycle.
Check this little code snippet that may be helpful to understand.
Private Class MyControl
Inherits NavronChartControl.UserControls.MyControlBase
Protected Overrides Sub OnChartTypeChanged(chartType As UserControls.ChartType)
MyBase.OnChartTypeChanged(chartType)
End Sub
///Call this OnChartTypeChanged(...) using some method
/// Or Create your public methods for your functionality
End Class
///Method at Parent Control
'OnChartTypeChanged is method that raise the event with argument
Protected Overridable Sub OnChartTypeChanged(chartType As ChartType)
'ChartTypeChang is an Event
RaiseEvent ChartTypeChanged(chartType)
End Sub
Check the Programming ASP.NET- Custom and User Controls 's Handling events in VB.NET section.
MSDN - Raising an Event - you can create your own custom event argument that hold some data that you want to pass through event. e.g. e.X

How can I call the Sub on the content page?

How can I call the Sub on the content page?
On the content page, there is let's say this:
Public Sub MySub()
End Sub
On the master page I have this:
Dim cph As ContentPlaceHolder = CType(Page.Form.FindControl("ContentPlaceHolder1"), ContentPlaceHolder)
Why do you need this? You can't be sure to have a particular contentpage. A Masterpage's purpose is re-usability and therefore many pages should use it. Why you need to access a special page?
What you could do is, add an event to the Masterpage, raise it when necessary and handle it in the ContentPage. For example...
in Master:
Partial Public Class ERPMaster
Inherits System.Web.UI.MasterPage
Public Event MasterLoaded(ByVal master As MasterPage)
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
RaiseEvent MasterLoaded(Me)
End Sub
In Content:
Private Sub Page_PreInit(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreInit
AddHandler DirectCast(Master, ERPMaster).MasterLoaded, AddressOf MasterLoaded
End Sub
Private Sub MasterLoaded(ByVal master As MasterPage)
MySub()
End Sub
Public Sub MySub()
End Sub
I assume that you are using ASP.NET?
Do you have a MasterType directive at the top of the content page file? If so, you can simply call functions on the master page using the following syntax:
Master.MySub()
The Master property of the content page is already typed to the page specified in the MasterType directive, so you can easily access any of the functions that it defines.
See MSDN for more information on interacting with master and client pages: http://msdn.microsoft.com/en-us/library/c8y19k6h(v=VS.100).aspx

Help with refreshed ASP.NET page clearing public array

Hey all, i am new at everything VB.net/ASP.net so i need some help with a problem i am currently having.
I have an ASCX.vb page that lets the user choose someone from a table. Once they do select someone, the page reloads with that persons information into another table below that one where they can submit an order for that person or remove that person.
Problem being is that i wanted to store the users ID that are selected but it seems that everytime the page reloads to show an update, it dim's my array again back to default.
This is my code once they choose a user:
Namespace prog.Controls
Partial Public Class progReportGrid
etc....
Public strIDArray() As String = {"0000770000"} 'Just a dummy place holder
Private Sub gvData_RowCommand(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewCommandEventArgs) Handles gvData.RowCommand
Dim idIndexNumber As Integer = Array.IndexOf(strIDArray, strID)
For i As Integer = 0 To strIDArray.Length - 1
System.Diagnostics.Debug.WriteLine(strIDArray(i))
Next
If idIndexNumber = -1 Then
ReDim Preserve strIDArray(strIDArray.Length)
strIDArray(strIDArray.Length) = strID
RaiseEvent EmployeeSelected(Me, New ESEventArgs(strID))
End If
End Sub
So everytime to page reloads the Public strIDArray() As String = {"0000770000"} gets called again and, of course, clears anything that was saved to it other than 0000770000.
How can i keep it from doing this?
UPDATE
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
'do what?
End If
End Sub
David
Perhaps you have a misunderstanding with the stateless model of a web application. Anything that is not stored in the ViewState or Session or a shared application variable will NOT persist through postbacks.
This means that when you declare your
Public strIDArray() As String
as a standard variable, it will be re initialized every time the page posts back.
For example, here's a simple flow of how this works:
The user opens their browser and opens up your aspx web page.
The request goes to your server, and all the controls including progReportGrid are instantiated as new instances and added to the page. (this is where your variable gets set to its original value every time)
A bunch of events are fired, including the Me.Load event
Controls that were added to the page are asked to generate their HTML
The HTML gathered from all the controls on the page is sent back to the user
So because your controls are all re-instantiated every post back, class variables like strIDArray are pretty much thrown out after the page is sent to the user.
Instead, if you want the page to remember what value the array had last postback and add more to it next postback, you have to use either ViewState, or Session.
For example:
Private Property StrIDArray() As String()
Get
If ViewState("StrIDArray") Is Nothing
ViewState("StrIDArray") = New String() {"0000770000"}
Return ViewState("StrIDArray")
End Get
Set(ByVal value As String())
ViewState("StrIDArray") = value
End Set
End Property
Now if you used this property instead of your variable, you could manipulate that array and as long as the user is on that page, the value of that array will persist across postbacks.
Use the Page.IsPostBack property in your Page_Load method.
This property is false for the first time the page loads and false for every postback afterwards.
If you set your default value strIDArray() = {"0000770000"} within If (Page.IsPostBack <> true) then it will not get reset on the postback.
EDIT : My VB syntax is VERY shaky but let me try it out
Partial Public Class EARNReportGrid
Begin
Public strIDArray() As String // DO NOT INITIALIZE it here. ONLY DECLARE IT
.....
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
//INITIALIZE the ARRAY
strIDArray = New String(){"00007700000"}
End If
End Sub
......
End

Resources