Error attempting to override HtmlGenericControl in ASP.NET 4.5 - asp.net

I have the following class:
Public Class HtmlGenericSelfClosingTag
Inherits HtmlGenericControl
Public Sub New()
MyBase.New()
End Sub
Public Sub New(tag As String)
MyBase.New(tag)
End Sub
Public Shadows Property TagName As String
Get
Return MyBase.TagName
End Get
Set(value As String)
MyBase.TagName = value
End Set
End Property
Public Overrides ReadOnly Property Controls As ControlCollection
Get
Throw New Exception("HtmlGenericSelfClosingTag cannot have child controls.")
End Get
End Property
Public Overrides Property InnerHtml As String
Get
Return String.Empty
End Get
Set(value As String)
Throw New Exception("InnerHtml cannot be set on an HtmlGenericSelfClosingTag")
End Set
End Property
Public Overrides Property InnerText As String
Get
Return String.Empty
End Get
Set(value As String)
Throw New Exception("InnerText cannot be set on an HtmlGenericSelfClosingTag")
End Set
End Property
Public Overrides Sub RenderControl(writer As HtmlTextWriter)
MyBase.Render(writer)
writer.Write(HtmlTextWriter.TagLeftChar & Me.TagName)
Attributes.Render(writer)
writer.Write(HtmlTextWriter.SelfClosingTagEnd)
End Sub
End Class
I have declared the control as:
Protected WithEvents MyElement As HtmlGenericSelfClosingTag
I have the html tag defined as:
<HtmlGenericSelfClosingTag ID="MyElement" runat="server" />
I am getting the following error during page render:
The base class includes the field 'MyElement', but its type (MyClass.HtmlGenericSelfClosingTag) is not compatible with the type of control (System.Web.UI.HtmlControls.HtmlGenericControl).
I have searched DuckDuckGo (and, by extension, Google, etc) to find out what else I need to override to make my class compatible with the HtmlGenericControl class, but no dice. I have also checked the MSDN docs but no mention of override requirements. Any ideas?

I was able to resolve the issue by removing the <HtmlGenericSelfClosingTag ID="MyElement" runat="server" /> tag from the aspx file, and simply adding the control directly in code, as in:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Me.head.Controls.AddAt(0, BaseElement)
End Sub
And to avoid rendering the control twice, I modified the Render code:
Public Overrides Sub RenderControl(writer As HtmlTextWriter)
writer.Write(HtmlTextWriter.TagLeftChar & Me.TagName)
Attributes.Render(writer)
writer.Write(HtmlTextWriter.SelfClosingTagEnd)
End Sub

Related

Custom LiteralControl does not insert into page

I am tired of creating a System.Web.UI.LiteralControl everytime I need to add a control to my in webforms. So, I decided that it would help me if I created a custom LiteralControl that initialized with that value.
So, I created this very simple class:
Public Class ScriptLiteralControl
Inherits System.Web.UI.LiteralControl
Private _Text As String
Public Sub New()
Me.InitControl()
End Sub
Private Sub InitControl()
Me._Text = "<script type=""text/none""></script>"
End Sub
Public Overrides Property Text As String
Get
Return Me._Text
End Get
Set(value As String)
Me._Text = value
End Set
End Property
End Class
But when I do this in my webpages:
dim slc as New ScriptLiteralControl
Me.Header.Controls.Add(slc)
Absolutely nothing gets added.
According to the ASP.NET documentation I've read, all I had to do was basically override the Text property in my implementation but that doesn't seem to be working.
Can someone tell me what obscure .net rule I am not following in my implementation?
You shouldn't have to override the Text property. I think that's what's causing your problem. Try this:
Public Class ScriptLiteralControl
Inherits System.Web.UI.LiteralControl
Public Sub New()
Me.Text = "Put your script text here"
End Sub
End Class

Raising User Control Event VB.NET and passing variable

I am delving into territory unfamiliar to me. I'm creating a User Control that I'd like to use across multiple forms. (thus reason for User Control). I am only familiar with VB.NET language. I've googled and I think I'm close to understanding, but I just can't figure this out. I've got multiple buttons on my User Control. When the "upload" button is pressed on my user control, I'd like it to run a Sub on my parent page called UploadFile(), which has one string parameter. I will have the UserControl on my page mulitple times like this:
<uc1:UploadFile ID="UploadFile1" runat="server" />
<uc1:UploadFile ID="UploadFile2" runat="server" />
In my code behind of the parent page, I'd like to execute this function on the Click event of the upload button within the user control. Where the unique parameters will then tell me what folders I will be uploading my file to. So that when user uploads a file within my first User Control on the page, it will run my Upload Sub on my parent page, take the parameter "a" and run my Sub that uploads my document and saves to database for files specific to "a" type. I will then tell the user control to change it's label to show that File A has been uploaded
Sub something somethingUploadFile1_Click
UploadFile("a")
End Sub
Sub something somethingUploadFile2_Click
UploadFile("b")
End Sub
Sub UploadFile(ByVal myString as string)
Select Case myString
Case "a"
If UploadFile1.FileUpload.HasFile Then
'run code to upload file
'display label
UploadFile1.lblReplaceMsg.Text = "File " & myString & " has been uploaded."
End If
Case "b"
If UploadFile2.FileUpload.HasFile Then
'run code to upload file
'display label
UploadFile2.lblReplaceMsg.Text = "File " & myString & " has been uploaded."
End If
End Select
End Sub
I know that in above code I'm supposed to be somehow referencing the button on my UserControl, but I'm not sure how to do it. I also know that Raising Events and Event Delegation are two major components of this, but again, I'm just not figuring it out. Can you please show me how to complete my code using the existing examples I provided?
Here is the complete code behind of my existing UserControl:
Public Class UploadFile
Inherits System.Web.UI.UserControl
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
End Sub
Protected Sub btnUpload_Click(sender As Object, e As EventArgs) Handles btnUpload.Click
End Sub
Protected Sub btnDelete_Click(sender As Object, e As System.Web.UI.ImageClickEventArgs) Handles btnDelete.Click
End Sub
Public Property lblViewFile() As Label
Get
Return _lblViewFile
End Get
Set(ByVal value As Label)
_lblViewFile = value
End Set
End Property
Public Property btnDelete() As ImageButton
Get
Return _btnDelete
End Get
Set(ByVal value As ImageButton)
_btnDelete = value
End Set
End Property
Public Property pnlUpload() As Panel
Get
Return _pnlUpload
End Get
Set(ByVal value As Panel)
_pnlUpload = value
End Set
End Property
Public Property FileUpload() As FileUpload
Get
Return _FileUpload
End Get
Set(ByVal value As FileUpload)
_FileUpload = value
End Set
End Property
Public Property btnUpload() As Button
Get
Return _btnUpload
End Get
Set(ByVal value As Button)
_btnUpload = value
End Set
End Property
Public Property lblReplaceMsg() As Label
Get
Return _lblReplaceMsg
End Get
Set(ByVal value As Label)
_lblReplaceMsg = value
End Set
End Property
Private _lblViewFile As Label
Private _btnDelete As ImageButton
Private _pnlUpload As Panel
Private _FileUpload As FileUpload
Private _btnUpload As Button
Private _lblReplaceMsg As Label
End Class
asp.net vb user control raising an event on the calling page
derive the arguments class you need from EventArgs according to your structure and data and use that.

Typecasting asp.net webControl to generic type with onClick event

I'm trying to find a way in which I can create a collection of various webControl's and then add a "onClick" event handler to these various controls, i've tried creating a reimplementation of "webControl" with a registered "onClick" event but I get a typecast error. Could anyone suggest how I could achieve this.
exception:
Exception Details: System.InvalidCastException: Unable to cast object of type 'System.Web.UI.WebControls.RadioButtonList' to type 'Club.WebControlButton'.
new webControl class:
<System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.Demand, Name:="FullTrust")> Public Class WebControlButton
Inherits WebControl
Implements IPostBackEventHandler
' Define the Click event.
Public Event Click As EventHandler
' Invoke delegates registered with the Click event.
Protected Overridable Sub OnClick(ByVal e As EventArgs)
RaiseEvent Click(Me, e)
End Sub
' Define the method of IPostBackEventHandler that raises change events.
Public Sub RaisePostBackEvent(ByVal eventArgument As String) _
Implements IPostBackEventHandler.RaisePostBackEvent
OnClick(New EventArgs())
End Sub
End Class
Private Sub AddOnClickStringsToElements()
Dim divider As Integer = If(onClickElements.Count > 0, onClickElements.Count, 1)
Dim percentIntervals As Integer = 100 / divider
For Each element As Tuple(Of String, WebControl, Integer) In onClickElements
If element.Item3 < 1 Then
element.Item2.Attributes("onClick") = GetAnimateJavascript(percentIntervals)
Else
element.Item2.Attributes("onClick") = GetAnimateJavascript(element.Item3)
End If
//throws typecast exception here
AddHandler CType(element.Item2, WebControlButton).Click, AddressOf UpdatePercent_OnClick
Next
End Sub
It looks like the onClickElements collection contains an actual RadioButtonList control, not a control which derives from your WebControlButton class.
Any control which you are putting into the onClickElements collection must derive from WebControlButton for that casting operation to work e.g.
Public Class MyRadioButtonList
Inherits WebControlButton
Protected Overrides Sub OnInit(ByVal e As System.EventArgs)
MyBase.OnInit(e)
' Create your radio button list here..
End Sub
End Class
An easier way would be to make an interface, such as IClickable...something a bit like this..sorry I didn't type it in VS so not sure if I got the syntax exact.
Public Interface IClickable
Public Event OnClick()
End Interface
Public Class MyRadioButtonList
Inherits RadioButtonList
Implements IClickable
Public Event OnClick Implements IClickable.OnClick
Private Sub RaiseOnClickEvent Handles Me.OnSelectedIndexChanged
RaiseEvent OnClick()
End Sub
End Class
And then..
For Each element As Tuple(Of String, WebControl, Integer) In onClickElements
If TypeOf(element.item2) Is IClickable Then
AddHandler CType(element.Item2, IClickable).OnClick, AddressOf UpdatePercent_OnClick
Else
Throw New Exception("A control of type IClickable was expected")
End If
Next

How to access controls and variables, across Class and Code-behind?

i have ASP.NET page, its code-behind, and a Class file:
Folder1/page.aspx (asp.net page), it contains a label:
<asp:Label runat="server" ID="Label1" Visible="false"></asp:Label>
Folder1/page.aspx.vb (code-behind), it calls connection.vb like this:
Dim x As New Connection
Protected Sub button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles button1.Click
x.checkusernameExists(TextBoxUsername.Text)
' I try to access `Boolean variable` Flag from Class file but I can't.
End Sub
App_Code/connection.vb (a class file that i created):
Public Class Connection
Public Sub checkusernameExists(ByVal username1 As String)
Dim flag as Boolean
' I try to access here `Label1.text` & `Label1.visible` to work on it but I can't.
End Sub
End Class
My Questions
1 - How can I access the Label1 from the ASP.NET page in Connection.vb?
2 - How can I access the Boolean variable from Connection.vb in page.aspx.vb (code behind)?
I am really stuck in this.
Thank you.
Use (public) properties or method parameters.
You have to ask yourself following: why should a class that is responsible for a connection(i assume to database) have access to your GUI at all? Don't hardlink different layers with each other, otherwise you won't be able to use them alone.
I would suggest to let the connection class do it's work and that is not to modify your frontend. Instead the controller (the aspx page) should manage it's GUI and call the connection class, using the return value to determine what to do next with the Label.
So return a Boolean to indicate if the user is valid:
Public Class Connection
Public Shared Function checkusernameExists(ByVal username1 As String)As Boolean
Dim userExists As Boolean
' acces db to check if the username exists '
Return userExists
End Sub
End Class
in your page:
Protected Sub button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles button1.Click
Dim userExists As Boolean = Connection.checkusernameExists(TextBoxUsername.Text)
Label1.Visible = userExists
If Label1.Visible Then Label1.Text = "Hello again " & TextBoxUsername.Text
End Sub
make flag as property and set this property in checkusernameExists function
Public Class Connection
Public Property Flag as Boolean
Public Sub checkusernameExists(ByVal username1 As String)
// set flag here
Flag = True // or whateever value returned from the database
' I try to access here `Label1.text` & `Label1.visible` to work on it but I can't.
End Sub
End Class
and access this instance level property in page.aspx.vb file
Dim x As New Connection
Protected Sub button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles button1.Click
x.checkusernameExists(TextBoxUsername.Text)
Label1.Visible= x.Flag;
' I try to access `Boolean variable` Flag from Class file but I can't.
End Sub
You can use Function to return value and pass label as parameter.
Public Function SaveChanges(ByRef Label1 As Label, ByVal username1 As String) As Boolean
{
Return True
}
It would be better if you pass the label properties to function instead of passing the object of label as it couple up two classes.

Populate TextBox From Public Property From Code-Behind

I am trying to use a property from the code-behind to populate a textbox instead of using in the code-behind textbox.text=. I am using vb.net. Here is the code for the aspx page:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContentPlaceHolder" runat="server">
<asp:TextBox runat="server" ID="roleTextBox" Text='<%# CurrentRole.Name%>'></asp:TextBox>
</asp:Content>
Here is the code behind code:
Imports Compass.UI.components
Imports Compass.Core.Domain
Imports Compass.Core.Domain.Model
Namespace app.administration.Roles
Partial Public Class edit
Inherits ClaimUnlockPage
Private _roleRepository As IRoleRepository
Private _roleId As Integer
Private _role As Role
Public Property CurrentRole() As Role
Get
Return _role
End Get
Set(ByVal value As Role)
_role = value
End Set
End Property
Public Property RoleRepository() As IRoleRepository
Get
Return _roleRepository
End Get
Set(ByVal value As IRoleRepository)
_roleRepository = value
End Set
End Property
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
LoadRole()
End Sub
Private Sub LoadRole()
_roleId = Config.RequestVal("id", Request)
_role = _roleRepository.GetById(_roleId)
End Sub
End Class
End Namespace
When I run the page the text box is empty.
I didn't see roleTextBox.text=value in your code! in LoadRole or anywhere.
And if you try to bind it, you need a static class for Role.
Just for testing try to add the following line in LoadRole
Private Sub LoadRole()
_roleId = Config.RequestVal("id", Request)
_role = _roleRepository.GetById(_roleId)
roleTextBox.text =CrrentRole.Name;
End Sub
if the roleTextBox is still empty then the CurrentRole.Name is empty.
As far as I know you can't bind a property of a control like this (I wish you could but I've never been able to figure out or find an example how to). The way I've always done it is create a protected function to return e.g.
Protected Function GetCurrentRoleName() As String
Return CurrentRole.Name
End Function
And in your markup bind like so
Text='<%# GetCurrentRoleName() %>'
You have to DataBind the container-control which contains your Textbox(f.e. a GridView,UserControl,etc.). So at least your aspx-page must be databound.
"When called on a server control, this method resolves all data-binding expressions in the server control and in any of its child controls."
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Me.CurrentRole = New Role("Administrator")
Me.DataBind() '!!!!!!!
End Sub
Private _currentRole As Role
Protected Property CurrentRole() As Role
Get
Return _currentRole
End Get
Set(ByVal value As Role)
_currentRole = value
End Set
End Property
Public Class Role
Public Sub New(ByVal name As String)
Me.Name = name
End Sub
Public Name As String
End Class
Then you can use your aspx-code to set the TextBox'-text property.

Resources