Showing completely different output based on the query-string - asp.net

I am trying to learn asp.net (vb.net) and I'm having some trouble. I want to change a pages content based on the querystring.
In classic asp I would do:
<% If request.querystring("page") = 1 THEN %>
-entire page-
<% Else %>
-different page-
<% End If %>
The closest I could get in .net is
Sub Page_Load(ByVal Sender as Object, ByVal E as EventArgs)
If Request.QueryString("page") = 1 Then
lblMessage1.Text = "message"
Else
lblMessage1.Text = "message2"
End If
End Sub
That only seems good for small things. What would be the best method to change an entire page?

You could do the following (simple redirect):
If Request.QueryString("page") = 1 Then
Response.Redirect("MyPage1.aspx")
Else
Response.Redirect("MyPage2.aspx")
End If
You could also do this (read more here):
If Request.QueryString("page") = 1 Then
Server.Transfer("MyPage1.aspx")
Else
Server.Transfer("MyPage2.aspx")
End If
And finally one more option (show/hide different panels on the page):
If Request.QueryString("page") = 1 Then
MyPanel1.Visible = true
MyPanel2.Visible = false
Else
MyPanel1.Visible = false
MyPanel2.Visible = true
End If

I would suggest using the MultiView control.
In a nutshell, you would create two multiview "Views", each with the html that you would want to show. Then you could look at the querystring parameter and switch the active view of the multiview accordingly.
This has a lot of advantages to Response.Redirect() like others suggested. First off, that would always generate at least two browser requests. Also, Response.Redirect() throws a ThreadAborted exception behind the scenes, which can confuse people diagnosing the application.
Example MultiView control:
ASPX:
<form id="form1" runat="server">
<div>
<asp:MultiView ID="MultiView1" runat="server">
<asp:View runat="server">
Hi, this is Page 1
</asp:View>
<asp:View runat="server">
Hi, this is Page 2
</asp:View>
</asp:MultiView>
</div>
</form>
Code:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
If Request.QueryString("page") = "1" Then
MultiView1.ActiveViewIndex = 0
Else
MultiView1.ActiveViewIndex = 1
End If
End Sub

You really have a few options, you could:
Response.Redirect(url) to a different page based on the input.
You could have an ASP:Panel with the "visible" property set to false and toggle that value based on the input.

Why not use different files instead? redirect to different pages. That would avoid having to have if statements everywhere.
OR
put your data in panels and just hide one or the other panel1.visible = (true/false). That's the best thing to do if you have to have it all in the same aspx page.

I prefer doing it on the ASPX page using DataBinding:
<asp:PlaceHolder runat="server" ID="Messages">
<asp:Label runat="server" Visible=<%# Request.QueryString("page") = 1 %> Text="Message 1" />
<asp:Label runat="server" Visible=<%# Request.QueryString("page") <> 1 %> Text="Message 2"/>
</asp:PlaceHolder>
Then on the server side:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
Messages.DataBind()
End Sub

For future reference, you can still use the classic ASP way to control content. Here's an ASPX page I wrote just now:
<%# Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!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">
<div>
<%
if (3 == 9)
{%>
<span>Hello</span>
<%
}
else
{
%> <span>What?</span > <%
}
%>
</div>
</form>
</body>
</html>
When the page renders, it displays 'What?' on the page.
However, I would say that this is bad practise and poor design! Use either womp's suggestion of a multiview, or a page redirect.

Related

How to databind a local variable in an ASPX template?

I have a UserControl named SlidingScaleTableReadonly with a bindable public member ScaleEntries, which take a List of struct instances. In the parent page, these lists are stored in a dictionary (InsulinSlidingScaleProtocolEntries), and I must render one SlidingScaleTableReadonly for each entry in this dictionary. Here's my template code so far:
<%# Register TagPrefix="uc" TagName="SlidingScaleTableReadonly" Src="~/Patient/SlidingScaleTableReadonly.ascx" %>
<asp:Content ContentPlaceHolderID="phContent" runat="server">
<h1>Échelles</h1>
<% For Each drug In InsulinSlidingScaleProtocolEntries %>
<h2><%= drug.Key %></h2>
<uc:SlidingScaleTableReadonly runat="server" ScaleEntries="<%# drug.Value %>" />
<% Next %>
</asp:Content>
My problem is at line 7:
BC30451 'drug' is not declared. It may be inaccessible due to its protection level.
If I replace drug.Value with a property available in code behind, the new variable can be found. I'm guessing it's not possible to directly data-bind local variables in ASPX? If that's the case, how can I use data-binding inside an iteration?
Edit - Changing the provenance of the bound value
I've changed the code a bit. Right after the "For Each" loop opening, a code-behind property named CurrentDrug is reassigned with the value of drug.Value, and uc:SlidingScaleTableReadonly get it's ScaleEntry from that new property. But that doesn't work either, the reassignment won't do shuck and ScaleEntry is always Nothing (or whatever initial value I gave to CurrentDrug).
Here's the new template:
<%# Register TagPrefix="uc" TagName="SlidingScaleTableReadonly" Src="~/Patient/SlidingScaleTableReadonly.ascx" %>
<asp:Content ContentPlaceHolderID="phContent" runat="server">
<h1>Échelles</h1>
<% For Each drug In InsulinSlidingScaleProtocolEntries
CurrentDrug = drug.Value %>
<h2><%= drug.Key %></h2>
<uc:SlidingScaleTableReadonly runat="server" ScaleEntries="<%# CurrentDrug %>" />
<% Next %>
</asp:Content>
And code-behind:
Public CurrentDrug As List(Of ScaleEntry)
Public Property InsulinSlidingScaleProtocolEntries As Dictionary(Of String, List(Of ScaleEntry))
'...
End Property
Edit - (Not) a solution: Stopped using aspx templates
I have to move on, and it seems like I'm not going to do any progress with aspx templates. I've rewritten the page so the UserControl is declared and inserted in code-behind. I think that's not how one should build an interface, that's not where that kind of logic should be place but I really want to move on.
Here's the new template code:
<asp:Content ContentPlaceHolderID="phContent" runat="server">
<h1>Échelles</h1>
<div id="scaleContainer" runat="server"></div>
</asp:Content>
Code-behind:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
For Each prescription In InsulinSlidingScaleProtocolEntries
Dim label As New HtmlGenericControl("h2") With {
.InnerText = prescription.Key
}
Dim table = CType(Page.LoadControl("~/Patient/SlidingScaleTableReadonly.ascx"), SlidingScaleTableReadonly)
table.ScaleEntries = prescription.Value
scaleContainer.Controls.Add(label)
scaleContainer.Controls.Add(table)
Next
End Sub
If you have a better solution, I'll be happy to see it.

Understanding UpdatePanels

I am trying to understand UpdatePanels and best practise for using them.
I am using .Net4.0 with VB.Net.
The idea is to create a conversation app for a clients website and so I have control called Convo.ascx. Code added below.
<asp:UpdatePanel runat="server">
<ContentTemplate>
<h2>Conversation</h2>
<p><asp:Literal ID="lit1" runat="server" /></p>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" Text="Button" />
</ContentTemplate>
</asp:UpdatePanel>
Convo.ascx.vb
Partial Class Convo
Inherits System.Web.UI.UserControl
Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
lit1.Text = lit1.Text & "<p>" & TextBox1.Text & "</p>"
End Sub
End Class
On a load page (Default.aspx) I have:
<%# Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" %>
<%# Reference Control="~/Convo.ascx" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:scriptmanager ID="Scriptmanager1" runat="server"></asp:scriptmanager>
<div>
<asp:UpdatePanel runat="server">
<ContentTemplate>
<asp:Button ID="Button1" runat="server" Text="Add Conversation" />
<asp:PlaceHolder ID="phConversation" runat="server">
</asp:PlaceHolder>
</ContentTemplate>
</asp:UpdatePanel>
</div>
</form>
</body>
</html>
With Codebehind Default.aspx.vb as
Partial Class _Default
Inherits System.Web.UI.Page
Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
AddConvo()
End Sub
Private Sub AddConvo()
Dim getPh As New PlaceHolder
getPh = CType(Me.FindControl("phConversation"), PlaceHolder)
Dim ucConvo As New Convo
ucConvo = CType(LoadControl("~/Convo.ascx"), Convo)
getPh.Controls.Add(ucConvo)
End Sub
Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
AddConvo()
End Sub
End Class
So the Convo I add OnLoad remains on the page after extra as been added been any convo added after load is gone once the button on Convo is hit.
So my question is, how can I have these add and remain? Eventually they will be added to database but right now I am trying to understand UpdatePanels as they will become the foundation for this app.
Is there a very good explanation of multi-use UpdatePanels anywhere?
Thanks in advance
PS, im a hobbiest so only VB responses please
The issue actually isn't with the UpdatePanel, but with ASP.NET. ASP.NET web forms uses a control hierarchy for the entire page, and you are adding the controls to the hierarchy "dynamically". Since you are doing it that way, ASP.NET requires you add the control back into the control hierarchy on every postback to the server. The UpdatePanel is a way to post back to the server, and therefore you must re-add the old user controls and new ones to that hierarchy.
Essentially the UpdatePanel was added to make AJAX easy, but you still have to work within the rules of ASP.NET.

intercept __doPostBack function

According to this post you can intercept the post by overriding this function __doPostBack but it wont work. If I view the generated source I am not able to see the function that is meant to be auto generated and causes asp.net to make the postback.
where is this function? and how do I intercept it?
I'm using asp.net 4 and vs 2012
Default.aspx
<%# Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script>
//breaks here as it cant find __doPostBack
var __original = __doPostBack;
__doPostBack = myFunction();
function myFunction() {
alert('intercept');
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox ID="TextBox1" runat="server" ></asp:TextBox>
<asp:Button ID="Button1" runat="server" Text="Button" />
</div>
</form>
</body>
</html>
Default.aspx.vb
Partial Class _Default
Inherits System.Web.UI.Page
Protected Sub form1_Load(sender As Object, e As EventArgs) Handles form1.Load
End Sub
Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim txt As String = TextBox1.Text
End Sub
End Class
An ASP.NET Button renders an <input type="submit" /> to postback the form, and will never use this method. The __doPostBack method is only used for elements that are not input buttons that do not normally cause a POST operation to the server. This is a function that's inside one of the Microsoft's JavaScript file, and only gets rendered out on the client. Common uses for __doPostBack are LinkButton controls, controls that may have AutoPostBack="true", and others.
Also, there may be a call to WebForms_DoPostBack... something named like that that also posts back, but internally calls __doPostBack.
If you are trying to prevent postback on click of your button, attach to the submit event of the form, and cancel the postback operation that way.

asp.net dropdown list postback to anchor

How can I go to an anchor tag on the page when the myDropDownList_SelectedIndexChanged() event fires?
I am using regular ASP.NET Forms.
Update: The following is valid for an ASP.NET Button. I would like to achieve the same functionality (going to #someAnchor) when I select an option from the Dropdown list.
<asp:Button ID="btnSubmit" runat="server" Text="Do IT" Width="186px" PostBackUrl="#myAnchor" CausesValidation="false" />
Update: I will try to further explain details that I didn't cover in enough detail initially.
This is a long page and in the middle of the page there is a dropdown list. Below the dropdown list is a label that will change based on the item selected from the dropdown. The update of the label will occur during the postback. At this point the page needs to remain focused on the dropdown. I tried to use AJAX to accomplish this, but other implementation details prevent that from working. The ability to go to an anchor tag after the postback would be a simple solution. Here is a simplified version of what I am trying to accomplish.
<%# Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
Protected Sub myDropDown_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs)
myLabel.Text = myDropDown.SelectedValue
'When this finishes, go to #myAnchor
End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
Imagine many lines of text here.
<a name="myAnchor"></a>
<asp:DropDownList ID="myDropDown" runat="server" OnSelectedIndexChanged="myDropDown_SelectedIndexChanged" asdf="asdf" PostBackUrl="#myAnchor"></asp:DropDownList>
<asp:Label ID="myLabel" runat="server"></asp:Label>
</div>
</form>
</body>
</html>
This could do the trick
<asp:DropDownList ID="DropDownList1" runat="server"
onchange="document.location= this.value">
<asp:ListItem Text="Anchor" Value="#anchor"></asp:ListItem>
<asp:ListItem Text="Anchor2" Value="#anchor2"></asp:ListItem>
</asp:DropDownList>
You mention myDropDownList_SelectedIndexChanged() (server code) but you must do it on client side, unless you have a good reason to go to the server
Add this to your page load and you will be good to go.
Page.MaintainScrollPositionOnPostBack = true;
I would use JavaScript--either register the script in your codebehind, or have an asp:Literal which is only visible after the SelectedIndexChanged event. Modify the location.href to append your anchor.
One way to do this is to use the forms.Controls bla bla bla properties in ASP.NET.
however I would suggest you to use a asp.net hyperlink control or link button and this would allow you to access it directly with its ID.
thanks,
MNK.
This requirement has simple javascript solution.But the problem is the design is flawed.Once you move to a new area in screen you cant access the navigation select list without scrolling back.Anyway something like the following works
<%# Page Language="C#" AutoEventWireup="true" CodeFile="Default3.aspx.cs" Inherits="Default3" %>
<!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>
<script type="text/javascript">
function Goto(x) {
window.location = "#"+x.value;
}
</script>
</head>
<body>
<select id="Select1" name="D1" onchange="Goto(this);">
<option value="Loc1" >go to 1 </option>
<option value="Loc2">go to 2 </option>
<option value="Loc3">go to 3 </option>
<option value="Loc4">go to 4 </option>
</select><form id="form1" runat="server">
</form>
<strong> <a href="#" id="Loc1" >Location 1</a></strong>
blah
<strong>Location 2</strong>
<strong>Location 3</strong>
<strong>Location 4</strong>
</body>
</html>
Here is what I have implemented to accomplish my desired result.
Protected Sub myDropDown_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles myDropDown.SelectedIndexChanged
Response.Redirect("Default.aspx?myDropDown=" & myDropDown.SelectedItem.Text.ToString.Trim & "#myAnchor")
End Sub
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
Dim myDropDownValue As String = Request.QueryString("myDropDown")
If myDropDownValue <> "" Then
myDropDown.Items.FindByText(myDropDownValue).Selected = True
Label1.Text = GetTextBasedOnDropDownSelection(myDropDownValue)
End If
End If
End Sub
If your dropdown list contains three items say for example:
Page1
Page2
Page3
Give the dropdownlist a property of AutoPostBack="true" and then in the dropdown OnSelectedIndexChanged method write the following:
if (DDl.SelectedIndex == 1) {
Response.Redirect("~/page1");
}
else if (DDl.SelectedIndex == 2) {
Response.Redirect("~/page2");
}

Accessing masterpage properties from child pages in ASP.net VB

I have masterpage.master.vb where I have properties, such as;
Private _SQLerror As String
Public Property SQLerror() As String
Get
Return _SQLerror
End Get
Set(ByVal value As String)
_SQLerror = String.Empty
End Set
End Property
Then I have an aspx page in which I need to use this property in, such as;
If **[masterpage property sqlerror]** = Nothing Then
InternalSQLErrLabel.Text = ("No Errors Reported")
End If
Can anyone give me an idea how to go about this? I've tried searching but most articles talk in the context of web controls...
Thanks.
Here you go:
How to: Reference ASP.NET Master Page Content
From the article, it looks like
If Master.SQLerror = Nothing Then
InternalSQLErrLabel.Text = ("No Errors Reported")
End If
should work for you.
Just be sure to add the MasterType directive as described or you might get a type conversion error. (Or you could use a variable of your master page type instead of Master, as daRoBBie suggests in his answer.)
I have created a test Web site just to test this out, and it works. Here is the full source of the site:
Site1.Master:
<%# Master Language="VB" AutoEventWireup="false" CodeBehind="Site1.master.vb" Inherits="WebApplication1.Site1" %>
<!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">
<div>
This is the Master Page content.
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
</div>
</form>
</body>
</html>
Site1.Master.vb:
Public Partial Class Site1
Inherits System.Web.UI.MasterPage
Private _SQLerror As String
Public Property SQLerror() As String
Get
Return _SQLerror
End Get
Set(ByVal value As String)
_SQLerror = String.Empty
End Set
End Property
End Class
WebForm1.aspx:
<%# Page Title="" Language="vb" AutoEventWireup="false" MasterPageFile="~/Site1.Master"
CodeBehind="WebForm1.aspx.vb" Inherits="WebApplication1.WebForm1" %>
<%# MasterType VirtualPath="~/Site1.Master" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
This is the Content Page content.
<asp:Label ID="InternalSQLErrLabel" runat="server" Text="Label"></asp:Label>
</asp:Content>
WebForm1.aspx.vb:
Public Partial Class WebForm1
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Master.SQLerror = Nothing Then
InternalSQLErrLabel.Text = ("No Errors Reported")
End If
End Sub
End Class
you can cast the masterpage to the correct type:
MyMasterPageType m = (MyMasterPageType)Master;
Then you can access your properties:
m.SqlError
If you have multiple master pages, let all your masterpages inherit from an interface, and cast the masterpage to that interface.
You can use <%# MasterType %> also for this.
If you have followed the steps in Andy West's answer and have one or many compile errors reading: Foo is not a member of 'System.Web.UI.MasterPage', make sure that they are the only compile error in your list. If there are any other compile errors that need to be fixed, they should be fixed before you continue troubleshooting your MasterPage.
These other compile errors may be preventing the compiler from parsing your MasterPage and detecting the extra properties. Once they are resolved, do a full recompile.

Resources