(MVC) MVC (2017 год)

My solution with Bootstrap modal window and Classic ASP.NET.

In bootstrap front-end framework there are many interracial element, that has different way and some difficulties to realization in classic ASP.NET, especially bootstrap modal.

At common, there are two different way to realize bootstrap modal window in classic ASP.NET - with ASP.NET postback and without postback. My solution to described below working with postback.

First of all, please let's see in to screen - how it look in the screen.

And how is possible to realize this solution in classic ASP.NET?

1. External user's interface.

In screen below you may see common scheme - to press button raises event PrepareDeleteOrder_Click, and when you decide to delete order, will be processing event DeleteOrder_Click.

This is external user's interface to my solution, but what exists inside in this solution? But to move farther we need to understand more about external interface of my solution. Let's look below.

First of all in ASP.NET before environment raise any event in body of program, will be working Form_load or another events, this my working in Form_prepender events because this is not a ASP.NET page (aspx), this is only a control (ASCX), and I want to prepare it to traveling to browser after main page is had prepared and full ready with data. So, my my Form_prepender looks like this:

This is main point of inside part of my solution, but we will speaking about it little bit later, because firstly we need to understand common postback structure of this solution, because this is ASP.NET.

   1:  Imports Extension3
   2:  Partial Class ProceedToCheckoutItem
   3:      Inherits CheckBasketCommon2
  22:          Dim AlertInterface1 As AlertInterface = Me.Page.FindControlRecursively("Alert1")

In preparation form to processing event, you may see two branch - when my form is only preparing to first traveling to browser. You may see, in this case modal window is hide.

  24:              AlertInterface1.Visible = False

Second part is more interesting, when postback will be arrived from modal window or from DeleteButton. Modal window will be open and show when alert control (with interface "AlertInterface1") stored special variables "AlertActionRequest".

  29:              'if false, this is postback from another button
  30:              Dim AlertActionRequest As Boolean = AlertInterface1.AlertActionRequest
  31:              If AlertActionRequest Then
  33:                  If AlertInterface1.TypeOfAlert = AlertPopupType.AlertType.DeleteOrder Then
  34:                      DeleteOrder_Click(DeleteOrder, Nothing)
  35:                  ElseIf AlertInterface1.TypeOfAlert = AlertPopupType.AlertType.SaveToLater Or AlertInterface1.TypeOfAlert = AlertPopupType.AlertType.RestoreSaved Then
  36:                      SaveItforLaterButton_Click(SaveItforLaterButton, Nothing)
  37:                  End If
  39:                  AlertInterface1.Visible = False

If user press "Delete Order", raises event PrepareDeleteOrder_Click that give access to Alert control (with AlertInterface1) and make two point setting in this control request "AlertPopupType.AlertType.DeleteOrder" and stored another information about order to deleting. In this case, if you has good understanding ASP.NET, this variable "AlertPopupType.AlertType.DeleteOrder" is a my own implementation of common ASP.NET postback variable __EVENTTARGET.

 757:      Protected Sub PrepareDeleteOrder_Click(sender As Object, e As EventArgs) Handles DeleteOrder.Click
 758:          Dim AlertInterface1 As AlertInterface = Me.Page.FindControlRecursively("Alert1")
 759:          AlertInterface1.TypeOfAlert = AlertPopupType.AlertType.DeleteOrder
 760:          Dim ClientName As String = CurrentBasketItem.Rows(ItemIndex)("FirstName").ToString & " " & CurrentBasketItem.Rows(ItemIndex)("LastName").ToString
 761:          AlertInterface1.SetOrderInfo("Are you sure, you want to delete " & ClientName & "'s order?", ClientName)
 762:          AlertInterface1.Visible = True
 763:          AlertInterface1.txtTitle = CurrentBasketItem.Rows(ItemIndex)("Title")
 764:          AlertInterface1.txtFirstname = CurrentBasketItem.Rows(ItemIndex)("Firstname")
 765:          AlertInterface1.txtLastName = CurrentBasketItem.Rows(ItemIndex)("LastName")
 775:      End Sub

If postback is arrive from browser with setting "AlertPopupType.AlertType.DeleteOrder" (and in background with other data) this is marker than this postback is arrive from popup window. And ProceedToCheckoutItem_PreRender sub is executing sub DeleteOrder_Click.

 777:      Protected Sub DeleteOrder_Click(sender As Object, e As EventArgs)
 786:              Dim AlertInterface1 As AlertInterface = Me.Page.FindControlRecursively("Alert1")
 787:              Basket.DeleteOrderFromBasket(Trim(RetailerID), _
 788:              AlertInterface1.txtTitle, _
 789:              AlertInterface1.txtFirstname, _
 790:              AlertInterface1.txtLastName, _
 821:      End Sub

If you have understanding common postbeck structure and external interface of this solution - let's going farther, to internal structure of solution.

2. Code of control with Delete button.

This is big code with many thousands line of code and in description of this it does not matter.

Main reason of this big hierarchy to move functions of control from external part of ASP.NET solution (what contains page part of ASP.NET application) to part of ASP.NET application in folder APP_CODE, where all functions is be available for all ASP.NET application.

3. External hugging control and ASP.NET Form

This form contains control that has repiter and this control is include in ASP.NET Form. At common, this is big code too. But most important part of this code is not a big.

This ASP.NET form contains two controls. And one of thw most important part of this solution - the script to hide Bootstrap modal window.

   1:  <%@ Page Title=" Language="VB" MasterPageFile="~/BasketInterface.master" AutoEventWireup="false" CodeFile="ProceedToCheckout.aspx.vb" Inherits="ProceedToCheckout" %>
   2:  <%@ Register Src="~/CheckBasket.ascx" TagPrefix="uc1" TagName="CheckBasket" %>
   3:  <%@ Register Src="~/Alert.ascx" TagPrefix="uc1" TagName="Alert" %>
  49:      <asp:ScriptManager ID="script1" runat="server"></asp:ScriptManager>
  50:      <uc1:CheckBasket runat="server" ID="CheckBasket1" />
  53:      <uc1:Alert runat="server" ID="Alert1" />
  54:      <script type="text/javascript" >
  55:         $("#ModalAlert").on("hidden.bs.modal", function () {
  56:         });
  57:      </script>

And this is main part of hugging control, that include control with delete button.

   1:  <%@ Control Language="VB" AutoEventWireup="false" CodeFile="CheckBasket.ascx.vb" Inherits="CheckBasket" %>
   2:  <%@ Register src="ProceedToCheckoutItem.ascx" tagname="ProceedToCheckoutItem" tagprefix="uc1" %>
  60:           <asp:DataList runat="server" ID="proceed_checkout" RepeatDirection="Vertical" RepeatLayout="Table" OnItemDataBound="proceed_checkout_ItemDataBound" style="width:100%">
  61:              <ItemTemplate>
  62:                 <uc1:ProceedToCheckoutItem ID="ProceedToCheckoutItem1"  runat="server" />
  63:              </ItemTemplate>
  64:           </asp:DataList>

4. Alert control.

Popup window (in my solution named Alert1) has three parts. First of it is ASP.NET markup.

Main part of this code is javascript code and two button. I search a way to create gray background over modal window but not found it.

   1:  <%@ Control Language="VB" AutoEventWireup="false" CodeFile="Alert.ascx.vb" Inherits="Alert" %>
   3:  <div id="ModalAlert" class="modal fade main-modal in"  tabindex="-1" role="dialog" aria-labelledby="myModalLabel" style="display: block; padding-right: 17px;">
   4:      <div class="modal-dialog" role="document">
   5:          <div class="modal-content" style="width: 600px;">
   6:              <div class="modal-header">
   7:                  <asp:LinkButton id="CloseModal" runat="server" CssClass="close" data-dismiss="modal" aria-label="Close" >
   8:                      <span aria-hidden="true">&times; </span>
   9:                  </asp:LinkButton>
  10:              </div>
  11:              <div class="modal-body" style="margin-left: 30px;">
  12:                  <asp:Label ID="MessageBody" runat="server" Font-Bold="True"></asp:Label><br />
  13:              </div>
  14:              <div class="modal-footer">
  15:                  <asp:Button ID="DeleteOrder" style="margin-left: 50px;" CssClass="btn btn-white btns-groups pull-left" runat="server" Text="Yes, delete order" />
  16:                  <asp:Button ID="NoDeleteOrder" CssClass="btn btn-white  btns-groups pull-right" runat="server" Text="No, continue shoping" />
  17:              </div>
  18:          </div>
  19:      </div>
  20:  </div>
  24:  <script type="text/javascript">
  25:      //problem - backdrop not working, but in browser console is work
  26:      //http://getbootstrap.com/customize/#modals
  27:      //https://www.w3schools.com/bootstrap/bootstrap_modal.asp
  28:      $("#ModalAlert").modal();
  29:      $("#ModalAlert").modal({ backdrop: true });
  30:  </script>

Second part of Popup window id code behind part. Its very simple:

   2:  Partial Class Alert
   3:      Inherits AlertInterface
   5:      Private Sub Alert_Load(sender As Object, e As EventArgs) Handles Me.PreRender
   6:          If Not IsPostBack Then
   7:              Me.AlertActionRequest = False
   8:          End If
   9:          If TypeOfAlert = AlertPopupType.AlertType.SaveToLater Then
  10:              'msg1.Text = "You wand save order to later"
  11:              DeleteOrder.Text = "Yes, save to later"
  12:          ElseIf TypeOfAlert = AlertPopupType.AlertType.DeleteOrder Then
  13:              'msg1.Text = "You wand to delete order"
  14:              DeleteOrder.Text = "Yes, delete order"
  15:          ElseIf TypeOfAlert = AlertPopupType.AlertType.RestoreSaved Then
  16:              'msg1.Text = "You wand to restore order to basket"
  17:              DeleteOrder.Text = "Yes, restore order"
  18:          End If
  19:      End Sub
  20:      Protected Sub DeleteOrder_Click(sender As Object, e As EventArgs) Handles DeleteOrder.Click
  21:          Me.InvokeEvent(Me.ClientName)
  22:          Me.AlertActionRequest = True
  23:          Me.Visible = False
  24:      End Sub
  25:      Protected Sub CloseModal_Click(sender As Object, e As EventArgs) Handles CloseModal.Click
  26:          Me.Visible = False
  27:      End Sub
  28:      Protected Sub NoDeleteOrder_Click(sender As Object, e As EventArgs) Handles NoDeleteOrder.Click
  29:          Me.AlertActionRequest = False
  30:          Me.Visible = False
  31:      End Sub
  32:  End Class

Both of part above is placed in part with page and its interface is inaccessible in all application, especially in ProceedToCheckoutItem control and another contror. Therefore most important part of this control has moved in App_code.

Most interesting part of this code you may see below.

   1:  Imports Microsoft.VisualBasic
   3:  Public Class AlertInterface
   4:      Inherits System.Web.UI.UserControl
   6:      Public Event DeleteOrderClick(ClientName As String)
   8:      Public Sub SetOrderInfo(MessageBody As String, ClientName As String)
   9:          Dim MessageBodyLabel As Label = Me.FindControl("MessageBody")
  10:          MessageBodyLabel.Text = MessageBody
  11:          Me.ClientName = ClientName
  12:      End Sub
  33:      Public Property AlertActionRequest As Boolean
  34:          Get
  35:              Return ViewState("AlertActionRequest")
  36:          End Get
  37:          Set(value As Boolean)
  38:              ViewState("AlertActionRequest") = value
  39:          End Set
  40:      End Property
  42:      Public Sub InvokeEvent(ClientName As String)
  43:          RaiseEvent DeleteOrderClick(ClientName)
  44:      End Sub
  46:      Public Property TypeOfAlert As AlertPopupType.AlertType
  47:          Get
  48:              Return ViewState("TypeOfAlert")
  49:          End Get
  50:          Set(value As AlertPopupType.AlertType)
  51:              ViewState("TypeOfAlert") = value
  52:          End Set
  53:      End Property
  64:      Public Property txtFirstname As String
  65:          Get
  66:              Return ViewState("txtFirstname")
  67:          End Get
  68:          Set(value As String)
  69:              ViewState("txtFirstname") = value
  70:          End Set
  71:      End Property
  73:      Public Property txtLastName As String
  74:          Get
  75:              Return ViewState("txtLastName")
  76:          End Get
  77:          Set(value As String)
  78:              ViewState("txtLastName") = value
  79:          End Set
  80:      End Property
 145:  End Class

What important in this code? First of all, event defined in this control is not working in ASP.NET. That need to understand any ASP.NET programmer, it is a correct syntax, but incorrect approach to move up information to high level from control. Correct solution is stored information (like AlertActionRequest) to Viewstate and check it in postback.

And second big important point that line 9 working! So, simple "findcontrol" in app_code may found anything ounside in APP_CODE part of application, in part with web forms. This is exception of common ASP.NET rules that means "only app_code part is accessible to any part of application, page part of all application will be create in runtime and not be accessible from code part". But in the same control page part is accebly by simple findcontrol function.

5. FindControlRecursively extension function - my common ASP.NET expanding.

But most interesting and difficult in ASP.NET (at common, and in this is most important part of my solution) - how to find Alert control in web form ProceedToCheckout.aspx?

Set of function from microsoft has only simple findcontrol function that working only in one level of included control. Therefore I expand standard set of ASP.NET function with my own function - FindControlRecursively, that check all level of control and can fount control Alert1 in ProceedToCheckout.aspx page.

This extension function is very important part of solution.

   1:  Imports Microsoft.VisualBasic
   3:  Public Module Extension0
   5:      <Runtime.CompilerServices.Extension()> _
   6:      Public Function FindControlRecursively(ByVal parentControl As Control, ByVal controlId As String) As Control
   8:          If String.IsNullOrEmpty(controlId) = True OrElse controlId = String.Empty Then
   9:              Return Nothing
  10:          End If
  12:          If parentControl.ID = controlId Then
  13:              Return parentControl
  14:          End If
  16:          If parentControl.HasControls Then
  17:              For Each c As Control In parentControl.Controls
  18:                  Dim child As Control = FindControlRecursively(c, controlId)
  19:                  If child IsNot Nothing Then
  20:                      Return child
  21:                  End If
  22:              Next
  23:          End If
  25:          Return Nothing
  27:      End Function
  28:  End Module

Happy programing in VB and Classic ASP.NET !

<00>  <01>  <02>  <03>  <04>  <05>  <06>  <07>  <08>  <09>  <10>  <11>  <12>  <13>  <14>  <15>  <16>  <17>  <18>  <19>  <20>  <21>  <22>  <23