How do I render the inner properties of my User Control on the page? - vb.net

I am designing a user control that attempts to create a filter bar with various TextBox or DropDownList elements on the page according to the sample markup below:
<gf:GridFilterBar runat="server">
<filters>
<filter Label="Field1" Type="TextBox" />
<filter Label="Field2" Type="DropDownList" />
</filters>
</gf:GridFilterBar>
Using inspiration from another post, I have created code behind that properly parses this markup and reads in the properties of each intended child control. The issue I am having is when it comes time to actually render this information on the screen. Every control I initialize from within the "New" sub of the "Filter" class never appears on the screen. When I place a breakpoint in the "New" sub and follow what is happening, I can see the Filter.New sub being traversed twice and the values being read in, but nothing else I initialize from within that sub has any effect on the page even though, as far as I can tell, it is all being created successfully. Here is a sample of the code with just the Label property being read:
Imports System
Imports System.Collections
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Public Class GridFilterBar
Inherits System.Web.UI.UserControl
Private _Filters As New FiltersClass(Me)
<PersistenceMode(PersistenceMode.InnerProperty)> _
Public ReadOnly Property Filters() As FiltersClass
Get
Return _Filters
End Get
End Property
Private Sub Page_Init(sender As Object, e As System.EventArgs) Handles Me.Init
DDL.Visible = True
End Sub
End Class
Public Class FiltersClass
Inherits ControlCollection
Public Sub New(ByVal owner As Control)
MyBase.New(owner)
End Sub
Public Overrides Sub Add(ByVal child As System.Web.UI.Control)
MyBase.Add(New Filter(child))
End Sub
End Class
Public Class Filter
Inherits HtmlGenericControl
Public Sub New(ByVal GenericControl As HtmlGenericControl)
Label = GenericControl.Attributes("Label")
Dim lit As New Literal
lit.Text = Label.ToString
Me.Controls.Add(lit)
End Sub
Public Property Label As String = String.Empty
Public Overrides Function ToString() As String
Return Me.Label
End Function
End Class
Can anyone spot what I'm doing wrong?

I was able to answer my question. I added an override sub for CreateChildControls in my main class and used a For Each loop to grab the properties set from each newly initialized "Filter"
Protected Overrides Sub CreateChildControls()
For Each filter In Filters
Dim lit As New Literal
lit.Text = filter.Label
Controls.Add(lit)
Next filter
End Sub
This relegated the Filter.New sub to simply grabbing the properties:
Public Sub New(ByVal GenericControl As HtmlGenericControl)
Label = GenericControl.Attributes("Label")
End Sub

Related

Remove Line Under ToolStrip VB.Net

I have added a ToolStrip to a form which is going to be used to add menus and set the background colour to match the forms background colour but it always displays a horizontal line under the ToolStrip which I find distracting.
My workaround so far is to use the StatusStrip and add dropdown buttons but ideally I would have liked to have used the ToolStrip as I believe this is the preferred tool for adding menus
Having researched this, I think it has something to do with the Render Property and I have read where it's been mentioned about creating an override.
Can anyone show me an example on how to achieve this in VB.Net please.
This is simply the VB.Net version of the code provided in this previous SO question.
Obviously, the line will be there at design-time on your form, but would be gone at run-time:
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
ToolStrip1.Renderer = New ToolStripRenderer
End Sub
Public Class ToolStripRenderer
Inherits ToolStripProfessionalRenderer
Public Sub New()
MyBase.New()
End Sub
Protected Overrides Sub OnRenderToolStripBorder(e As ToolStripRenderEventArgs)
If Not (TypeOf e.ToolStrip Is ToolStrip) Then
MyBase.OnRenderToolStripBorder(e)
End If
End Sub
End Class
End Class
An alternative would be to create a whole new class that inherits from ToolStrip and creates the renderer for you. Then the line would be gone at design-time as well. The new control would appear at the top of your ToolBox after you compile. Unfortunately, this means you'd have to delete the old ToolStrip and drag a new one (your version) onto the form and reconfigure it:
Public Class MyToolStrip
Inherits ToolStrip
Public Sub New()
MyBase.New
Me.Renderer = New ToolStripRenderer
End Sub
Public Class ToolStripRenderer
Inherits ToolStripProfessionalRenderer
Public Sub New()
MyBase.New()
End Sub
Protected Overrides Sub OnRenderToolStripBorder(e As ToolStripRenderEventArgs)
If Not (TypeOf e.ToolStrip Is ToolStrip) Then
MyBase.OnRenderToolStripBorder(e)
End If
End Sub
End Class
End Class
Thank you for explaining how to do that. I went with the second option as this seemed more convenient for what I wanted and I presume I can save that Class and reuse it on further projects.
I still need to learn the Class and explore what and how they can be used.
Public Class MyToolStrip
Inherits ToolStrip
Public Sub New()
MyBase.New
Me.Renderer = New ToolStripRenderer
End Sub
Public Class ToolStripRenderer
Inherits ToolStripProfessionalRenderer
Public Sub New()
MyBase.New()
End Sub
Protected Overrides Sub OnRenderToolStripBorder(e As ToolStripRenderEventArgs)
If Not (TypeOf e.ToolStrip Is ToolStrip) Then
MyBase.OnRenderToolStripBorder(e)
End If
End Sub
End Class
End Class
Here is a screenshot of what I am referring to
I have made the Toolstrip the same colour as the Panel I have put it into.
Underneath the Toolstrip is a white line which I find distracting and would like to be able to remove it.

Calling functions outside class

what is the correct way to call function outside the class, below code is also working
tried an alternate way by using delegate but couldn't figure out to pass function with parameters from Form class to classname so that form function can be called.
Public class form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
dim cl as new classname
cl.run()
end sub
function testmsg(txt as string)
msgbox(txt)
end function
end class
public class classname
public sub run()
txt = "xyz"
if(condition = true) then call form1.testmsg(byref txt as string)
end sub
end class
You can at any time, and in any place, and from a form, a class object, or even just standard vb module call/use a function (or in your case, it should be a sub).
Just mark any routine (sub/function) in the form as public.
eg:
Public function testmsg(txt as string)
msgbox(txt)
end function
NOw, in any other form, class or in fact any place you have code, you can thus go:
FormA.TestMsg("hi from form B")
so, there are no restrictions here. And any form wide scoped variables marked as public can also be used:
eg:
Public Class FormA
Public Zoo As String
Public Function TestMsg(txt As String)
MsgBox(txt)
End Function
Public Sub ShowZoo()
MsgBox("value of zoo = " & Zoo)
End Sub
End Class
So above is FormA
Now, any code from any ohter form, class or whatever can do this:
FormA.TestMsg("hi from form B")
FormA.Zoo = "this is zoo value"
FormA.ShowZoo()
So, just mark any variable as public (it in effect becomes a public property of that form).
And, just mark any function/Sub as pubic (it in effect becomes a public "method" of that form.

Access a base class property in inheritance class

I'm using the base class Button in VB.net (VS2017) to create a new class called CDeviceButton. The CDeviceButton then forms as a base for other classes such as CMotorButton, CValveButton.
I want to set the Tag property in the child class CMotorButton but access it in the constructor in CDeviceButton. Doesn't work for me. It turns up being empty.
The Tag is set in the standard property when inserting the CMotorButtom instance into a form.
I've also tried to ensure teh the parent classes' constructors are run by setting mybase.New() as the first action in each constructor but that didn't change anything.
Any ideas for improvements?
Public Class CDeviceButton
Inherits Button
Public MMIControl As String = "MMIC"
Public Sub New()
MMIControl = "MMIC" & Tag
End Sub
End class
Public Class CMotorButton
Inherits CDeviceButton
Sub New()
'Do Something
end Sub
End Class
When you try to concatenate Tag with a string, you are trying to add an object that is probably nothing. I set the Tag property first and used .ToString and it seems to work.
Public Class MyButton
Inherits Button
Public Property MyCustomTag As String
Public Sub New()
'Using an existing Property of Button
Tag = "My Message"
'Using a property you have added to the class
MyCustomTag = "Message from MyCustomTag property : " & Tag.ToString
End Sub
End Class
Public Class MyInheritedButton
Inherits MyButton
Public Sub New()
If CStr(Tag) = "My Message" Then
Debug.Print("Accessed Tag property from MyInheritedButton")
Debug.Print(MyCustomTag)
End If
End Sub
End Class
And then in the Form
Private Sub Test()
Dim aButton As New MyInheritedButton
MessageBox.Show(aButton.Tag.ToString)
MessageBox.Show(aButton.MyCustomTag)
End Sub
Below is my solution I came up with that works. Basically I make sure that all initialization has taken place before reading the Tag property. What I experienced is that the Tag property is empty until the New() in CMotorButton has completed, even though the Tag property has been set when creating the instance of CMotorButton in the Form. TimerInitate has a Tick Time of 500 ms.
Not the most professional solution but works for what I need at the moment.
Another option could be multi threading but that I haven't tried and leave that for future tryouts.
Public Class CDeviceButton
Inherits Button
Public MMIControl As String = "MMIC"
Public Sub New()
TimerInitiate = New Timer(Me)
End Sub
Private Sub TimerInitiate_Tick(sender As Object, e As EventArgs) Handles TimerInitiate.Tick
If Tag <> Nothing Then
TimerInitiate.Stop()
MMIControl = "MMIC" & Tag
End If
End Sub
End class
Public Class CMotorButton
Inherits CDeviceButton
Sub New()
'Do Some stuff
TimerInitiate.Start()
End Sub
Private Sub CMotorButton_Click(sender As Object, e As EventArgs) Handles Me.Click
End Class

How to get inherited type of Form in ControlDesigner

I am building a custom designer that will associate a control with a business property on the form. The form DealUI has properties Instrument and Product, which are a business items:
Public Class DealUI
Inherits System.Windows.Forms.Form ' repetition of Inherits in Deal.Designed.vb, just to make the point
Sub New()
InitializeComponent()
End Sub
<Business(True)> _
Public Property Product As String
<Business(True)> _
Public Property Instrument As String
End Class
The Business attribute is simply
NotInheritable Class BusinessAttribute
Inherits Attribute
Private _isBusiness As Boolean
Sub New(isBusiness As Boolean)
_isBusiness = isBusiness
End Sub
End Class
The form contains a custom control, ProductTextBox of type PilotTextBox:
<DesignerAttribute(GetType(PilotControlDesigner)), _
ToolboxItem(GetType(PilotToolboxItem))> _
Public Class PilotTextBox
Inherits TextBox
Public Property Source As String
End Class
In the designer, when the selected control changes to ProductTextbox, I want to populate its Source property with the names of the Form's properties that have the BusinessAttribute (Instrument and Product), the user can then choose between Instrument and Product. The designer code is
Public Class PilotControlDesigner
Inherits ControlDesigner
Private Sub InitializeServices()
Me.selectionService = GetService(GetType(ISelectionService))
If (Me.selectionService IsNot Nothing) Then
AddHandler Me.selectionService.SelectionChanged, AddressOf selectionService_SelectionChanged
End If
End Sub
Private Sub selectionService_SelectionChanged(ByVal sender As Object, ByVal e As EventArgs)
If Me.selectionService IsNot Nothing Then
If Me.selectionService.PrimarySelection Is Me.Control Then
Dim form As Object = DesigningForm()
If form IsNot Nothing Then
For Each prop As PropertyInfo In form.GetType.GetProperties
Dim attr As Attribute = GetCustomAttribute(prop.ReflectedType, GetType(BusinessAttribute), False)
If attr IsNot Nothing Then
' we've found a Business attribute
End If
Next
End If
End If
End If
End Sub
Private Function DesigningForm() As Object ' in fact, a form, or more precisely something that inherits from Form
Dim host As IDesignerHost = CType(Me.Component.Site.GetService(GetType(IDesignerHost)), IDesignerHost)
Dim container As IContainer = host.Container
For Each comp As Component In container.Components
If comp.GetType.IsAssignableFrom(GetType(Form)) Then ' or anything that inherits 'Form'
return comp ' returns a Form, not a Deal!!
End If
Next comp
Return nothing
End Function
End Class
The selected control is a Deal (which inherits from Form), but the component in the designer is a Form, not a Deal (!! in the comment). I need to examine the Instrument and Product properties, which only exist on a Deal.
How can I obtain the Deal object in the designer?

How can I access form.aspx from codefile.aspx.vb?

I have a formview on a page called form.aspx and it of course has a code-behind page called form.aspx.vb
The form.aspx.vb file is huge! So I'd like to take the functions out of the form.aspx.vb page and into functions.vb.
My problems is everything goes out of scope.
example....
form.aspx.vb has this...
dim box1, box2, box3 as Textbox
Public Sub initialiseControls()
box1 = Me.Formview1.FindControl("box1")
box2 = Me.Formview1.FindControl("box2")
box3 = Me.Formview1.FindControl("box3")
End Sub
I'd like to take this sub and put it into functions.vb codefile, but everything is out of scope then.
Can someone tell me if this can be done?
Thanks.
Two options:
1) Pass a reference to the Page into every method that needs to use it:
In code behind:
ExTest.ModifyControl(Me.Page)
New class with various methods in:
Public Class ExTest
Public Shared Sub ModifyControl(aPage As System.Web.UI.Page)
Dim tb As TextBox = CType(aPage.FindControl("txthelloWorld"), TextBox)
tb.Text = "Hello World"
End Sub
End Class
2) Extend the code behind as a partial class:
Current code behind (add the Partial keyword):
Partial Public Class WebForm1
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
ModifyControl()
End Sub
End Class
Add a New class:
Partial Public Class WebForm1
Private Sub ModifyControl()
txtGoodbyeWorld.Text = "Goodbye"
End Sub
End Class