Imports System Imports System.Web Imports System.Web.UI Imports System.Web.UI.WebControls Imports System.Collections.Specialized Namespace Stonebroom Public Class StandardSpinBox ' specify base class to extend Inherits WebControl ' need to be able to handle postbacks Implements IPostBackDataHandler ' ---------------------------------------------- ' private internal member variables Private _autopostback As Boolean = False Private _columns As Integer = 3 Private _cssclass As String = "" Private _increment As Integer = 1 Private _maxvalue As Integer = 99 Private _minvalue As Integer = 0 Private _text As String = "" ' to hold child control references Private oTextBox As TextBox Private oImageUp, oImageDown As ImageButton ' ---------------------------------------------- ' public event Public Event ValueChanged As EventHandler ' ---------------------------------------------- ' public constructor Public Sub New() ' call base method first with element type ' root element for control will be a SPAN MyBase.New("span") End Sub ' ---------------------------------------------- OverRides Protected Sub OnInit(e As EventArgs) ' first event that control can handle ' must always call base method first MyBase.OnInit(e) ' must register to receive postback events ' required because "root" control is a SPAN ' does not receive postback events by default Page.RegisterRequiresPostBack(Me) End Sub ' ---------------------------------------------- Overridable Function LoadPostData(key As String, _ vals As NameValueCollection) _ As Boolean _ Implements IPostBackDataHandler.LoadPostData ' occurs when data in postback is available to control ' get value from postback collection Dim NewValue As String = vals(key & "_textbox") ' get value from viewstate - i.e. when page was last created Dim ExistingValue As String = ViewState(key & "_textbox") If NewValue <> ExistingValue Then ' value in control has been changed by user ' set internal member to posted value and write message ' return True so PostDataChangedEvent will be raised _text = NewValue Context.Trace.Write("LoadPostData:" & key, "Loaded new value '" _ & NewValue & "' from postback data") Return True Else ' value in control has not changed ' set internal member to viewstate value and write message ' return False because no need to raise ValueChanged event _text = ExistingValue Context.Trace.Write("LoadPostData:" & key, "Loaded existing value '" _ & ExistingValue & "' from viewstate") Return False End If End Function ' ---------------------------------------------- Overridable Sub RaisePostBackDataChangedEvent() _ Implements IPostBackDataHandler.RaisePostDataChangedEvent ' called after all controls have loaded postback data, ' but only if LoadPostData handler (above) returned True ' call event handler for ValueChanged event OnValueChanged(EventArgs.Empty) End Sub ' ---------------------------------------------- Protected OverRidable Sub OnValueChanged(e As EventArgs) ' write message to Trace and raise the public ValueChanged ' event with appropriate EventArgs values Context.Trace.Write("OnValueChanged:" & Me.UniqueID, _ "Raising ValueChanged event") RaiseEvent ValueChanged(Me, e) End Sub ' ---------------------------------------------- ' public property accessor declarations Public Property AutoPostback As Boolean Get Return _autopostback End Get Set _autopostback = value End Set End Property Public Property Columns As Integer Get Return _columns End Get Set If (value > 0) And (value < 1000) Then _columns = value Else Throw New Exception("Columns must be between 1 and 999") End If End Set End Property Public OverRides Property CssClass As String Get Return _cssclass End Get Set _cssclass = value End Set End Property Public Property Increment As Integer Get Return _increment End Get Set If value > 0 Then _increment = value Else Throw New Exception("Increment must be greater than zero") End If End Set End Property Public Property MaximumValue As Integer Get Return _maxvalue End Get Set If value > _minvalue Then _maxvalue = value Else Throw New Exception("MaximumValue must be greater than " _ & "the current MinimumValue") End If End Set End Property Public Property MinimumValue As Integer Get Return _minvalue End Get Set If value < _maxvalue Then _minvalue = value Else Throw New Exception("MinimumValue must be less than " _ & "the current MaximumValue") End If End Set End Property Public Property Text As String Get Return _text End Get Set Dim iValue As Integer Try iValue = Int32.Parse(value) Catch Throw New Exception("Text property must represent " _ & "a valid Integer value") End Try If (value >= _minvalue) And (value <= _maxvalue) _text = value SetMaxMinValues() Else Throw New Exception("Text property must be within" _ & "the current MinimumValue and MaximumValue") End If End Set End Property Public Property Value As Integer Get Try Return Int32.Parse(_text) Catch End Try End Get Set If (value >= _minvalue) And (value <= _maxvalue) _text = value.ToString() Else Throw New Exception("Value property must be within the " _ & "current MinimumValue and MaximumValue") End If End Set End Property ' ---------------------------------------------- OverRides Protected Sub CreateChildControls() ' called when its time to create the child controls ' create HTML elements and ASP.NET server controls ' set properties and add to Controls collection ' control ID prefix for contained controls Dim sCID As String = Me.UniqueID & "_" ' check if value is within max and min limits SetMaxMinValues() ' set properties (attributes) of root SPAN element Me.Style("position") = "relative" ' save current value of Textbox in viewstate ViewState(sCID & "textbox") = _text Context.Trace.Write("CreateChildControls:" & Me.UniqueID, _ "Saved value '" & _text & "' in viewstate") ' create Textbox control, set properties ' and add to Controls collection oTextBox = New TextBox() With oTextBox .id = sCID & "textbox" If _cssclass <> "" Then .CssClass = _cssclass End If .Columns = _columns .Style("top") = "0" .Style("left") = "0" .Style("width") = _columns * 10 .Style("text-align") = "right" .Text = _text End With Controls.Add(oTextBox) ' create "up" ImageButton control, set ' properties and add to Controls collection oImageUp = New ImageButton() With oImageUp .id = sCID & "imageup" .Style("position") = "absolute" .Style("top") = "0" .Style("left") = oTextBox.Style("width") .Width = New Unit(16) .Height = New Unit(10) .ImageUrl = "~/images/spin-up.gif" .AlternateText = "+" & _increment.ToString() .BorderStyle = BorderStyle.None .BorderWidth = New Unit(0) .Attributes.Add("border", "0") End With Controls.Add(oImageUp) ' create "down" ImageButton control, set ' properties and add to Controls collection oImageDown = New ImageButton() With oImageDown .id = sCID & "imagedown" .Style("position") = "absolute" .Style("top") = "10" .Style("left") = oTextBox.Style("width") .Width = New Unit(16) .Height = New Unit(10) .ImageUrl = "~/images/spin-down.gif" .AlternateText = "-" & _increment.ToString() .BorderStyle = BorderStyle.None .BorderWidth = New Unit(0) .Attributes.Add("border", "0") End With Controls.Add(oImageDown) ' create true/false string for JavaScript code Dim sAutoPostback As String = "false" If _autopostback Then sAutoPostback = "true" End If ' create JavaScript parameter string - used to set ' parameters for client-side control event handlers Dim sParams As String = "'" & sCID & "textbox', " _ & _minvalue.ToString() & ", " _ & _maxvalue.ToString() & ", " _ & _increment.ToString() & ", " _ & sAutoPostback ' see if previous instance of this control has already ' added the required JavaScript code to the page If Not Page.IsClientScriptBlockRegistered("StonebroomSpinBox") Then Dim sPath As String = "/aspnet_client/custom/" Dim sScript As String = "<script language='javascript' " _ & "src='" & sPath & "spinbox.js'><" & "/script>" ' add this JavaScript code to the page Page.RegisterClientScriptBlock("StonebroomSpinBox", sScript) End If ' set client-side event handlers for controls oImageUp.Attributes.Add("onclick", "return incrementValue(" & sParams & ")") oImageDown.Attributes.Add("onclick", "return decrementValue(" & sParams & ")") oTextBox.Attributes.Add("onblur", "return checkValue(" & sParams & ")") oTextBox.Attributes.Add("onkeydown", "return keyDown(event, " & sParams & ")") ' display control property values in Trace Context.Trace.Write("Property Values", Me.UniqueID _ & ".AutoPostback = " & Me.AutoPostback.ToString()) Context.Trace.Write("Property Values", Me.UniqueID _ & ".Columns = " & Me.Columns.ToString()) Context.Trace.Write("Property Values", Me.UniqueID _ & ".CssClass = '" & Me.CssClass & "'") Context.Trace.Write("Property Values", Me.UniqueID _ & ".Increment = " & Me.Increment.ToString()) Context.Trace.Write("Property Values", Me.UniqueID _ & ".MaximumValue = " & Me.MaximumValue.ToString()) Context.Trace.Write("Property Values", Me.UniqueID _ & ".MinimumValue = " & Me.MinimumValue.ToString()) Context.Trace.Write("Property Values", Me.UniqueID _ & ".Text = '" & Me.Text & "'") Context.Trace.Write("Property Values", Me.UniqueID _ & ".Value = " & Me.Value.ToString()) End Sub ' ---------------------------------------------- ' check if current value of Textbox (in _text member variable) ' is within current max and min limits, and reset if not Private Sub SetMaxMinValues() Dim iValue As Integer Try iValue = Int32.Parse(_text) Catch iValue = _minvalue End Try If iValue < _minvalue Then iValue = _minvalue End If If iValue > _maxvalue Then iValue = _maxvalue End If _text = iValue.ToString() End Sub ' ---------------------------------------------- End Class End Namespace