VB.NET Imports without project name - vb.net

My form only works when I use
Imports WindowsApplication1.FrameGrabber
but not when I use
Imports FrameGrabber
I will be using the FrameGrabber in several different projects, so I would really prefer having only to say "Imports FrameGrabber".
My "FrameGrabber / CameraWindow" is defined like this:
Imports System.Collections
Imports System.ComponentModel
Imports System.Drawing
Imports System.Data
Imports System.Windows.Forms
Imports System.Threading
Namespace FrameGrabber
''' <summary>
''' Summary description for CameraWindow.
''' </summary>
Public Class CameraWindow
Inherits System.Windows.Forms.Control
Private m_camera As Camera = Nothing
Private m_autosize As Boolean = False
Private needSizeUpdate As Boolean = False
Private firstFrame As Boolean = True
' AutoSize property
<DefaultValue(False)> _
Public Overrides Property AutoSize() As Boolean
Get
Return m_autosize
End Get
Set(value As Boolean)
m_autosize = value
UpdatePosition()
End Set
End Property
' Camera property
<Browsable(False)> _
Public Property Camera() As Camera
Get
Return m_camera
End Get
Set(value As Camera)
' lock
Monitor.Enter(Me)
' detach event
If m_camera IsNot Nothing Then
RemoveHandler m_camera.NewFrame, AddressOf Me.pCameraWindow_NewFrame
End If
m_camera = value
needSizeUpdate = True
firstFrame = True
' atach event
If m_camera IsNot Nothing Then
AddHandler m_camera.NewFrame, AddressOf Me.pCameraWindow_NewFrame
End If
' unlock
Monitor.[Exit](Me)
End Set
End Property
' Constructor
Public Sub New()
InitializeComponent()
SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.DoubleBuffer Or ControlStyles.ResizeRedraw Or ControlStyles.UserPaint, True)
End Sub
#Region "Windows Form Designer generated code"
Private Sub InitializeComponent()
Me.SuspendLayout()
Me.ResumeLayout(False)
End Sub
#End Region
' Paint control
Protected Overrides Sub OnPaint(pe As PaintEventArgs)
If (needSizeUpdate) OrElse (firstFrame) Then
UpdatePosition()
needSizeUpdate = False
End If
' lock
Monitor.Enter(Me)
Dim g As Graphics = pe.Graphics
Dim rc As Rectangle = Me.ClientRectangle
If m_camera IsNot Nothing Then
Try
m_camera.Lock()
' draw frame
If m_camera.LastFrame IsNot Nothing Then
g.DrawImage(m_camera.LastFrame, rc.X + 1, rc.Y + 1, rc.Width - 2, rc.Height - 2)
firstFrame = False
Else
' Create font and brush
Dim drawFont As New Font("Arial", 12)
Dim drawBrush As New SolidBrush(Color.White)
g.DrawString("Connecting ...", drawFont, drawBrush, New System.Drawing.PointF(5, 5))
drawBrush.Dispose()
drawFont.Dispose()
End If
Catch generatedExceptionName As Exception
Finally
m_camera.Unlock()
End Try
End If
' unlock
Monitor.[Exit](Me)
MyBase.OnPaint(pe)
End Sub
Public Function getImage() As Image
If Not m_camera Is Nothing Then
If Not m_camera.LastFrame Is Nothing Then
Return m_camera.LastFrame
End If
End If
Return Nothing
End Function
' Update position and size of the control
Public Sub UpdatePosition()
' lock
Monitor.Enter(Me)
If (m_autosize) AndAlso (Me.Parent IsNot Nothing) Then
Dim rc As Rectangle = Me.Parent.ClientRectangle
Dim width As Integer = 320
Dim height As Integer = 240
If m_camera IsNot Nothing Then
m_camera.Lock()
' get frame dimension
If m_camera.LastFrame IsNot Nothing Then
width = m_camera.LastFrame.Width
height = m_camera.LastFrame.Height
End If
m_camera.Unlock()
End If
'
Me.SuspendLayout()
Me.Location = New Point((rc.Width - width - 2) \ 2, (rc.Height - height - 2) \ 2)
Me.Size = New Size(width + 2, height + 2)
Me.ResumeLayout()
End If
' unlock
Monitor.[Exit](Me)
End Sub
' On new frame ready
Private Sub pCameraWindow_NewFrame(sender As Object, e As System.EventArgs)
Invalidate()
End Sub
End Class
End Namespace
Thank you for the help!

You need to change the Root Namespace for your project or override it. When you wrap your class in a Namespace block (e.g. Namespace FrameGrabber), the given namespace is relative to the root namespace for your project. In other words, if your root namespace is WindowsApplication1, then when you say Namespace FrameGrabber, all the enclosed types will actually be in the WindowsApplication1.FrameGrabber namespace.
If you want to override the root name space for one section of code, you can use the Global keyword so that the namespace declaration is not relative, like this:
Namespace Global.FrameGrabber
' ...
End Namespace
Using the Global keyword in your namespace declaration, like that, to override the root namespace seems to be a recent addition to VB.NET, though. From what I can tell, based on the inclusion of the information about it in the MSDN article, support for that was added in Visual Studio 2012. You can also find information on it in this MSDN article:
The Global keyword can also be used in a Namespace statement. This lets you define a namespace out of the root namespace of your project. For more information, see the "Global Keyword in Namespace Statements" section in Namespaces in Visual Basic.
Another option is to remove the root namespace from your project properties and then declare the full namespace on each and every code file in your project. The setting can be found in the project settings designer screen: My Project > Application > Root namespace.
Either that or come up with a naming convention that is more conducive to VB.NET's eccentricity. For instance, if you made the root namespace for your project your company name, then MyCompany.FrameGrabber would certainly make more sense than WindowsApplication1.FrameGrabber.

Related

System.IO.FileNotFoundException and AutoCAD Support File Search Path

I'm creating a program that has a "rehost workflowdesigner" (like Autodesk SubAssembly Composer did) and it fails to create the toolbox controls.
The error that occurs:
System.IO.FileNotFoundException: Could not load file or assembly....
So far I understand that, because the DLL is not in the GAC, windows cannot find it.
So I tested the following hypotheses:
NETLOAD for the first time, without setting DLL folder in "support file search path"
when calling the command, result: ERROR
Add the DLL folder to the "support file search path" and then NETLOAD
when calling the command, result: WORKS
Enable autoload by the "LOADCTRLS" key (defined in IExtensionApplication.Initialize), without adding the DLL in the "support file search path"
when calling the command, result: ERROR
Now that the dll is loaded by the registry ("LOADCTRLS" ), still without the "support file search path"
when calling the command, result: ERROR
In the same cad session as in step 4, add the DLL to the ""support file search path", editing the field without clicking the "Browse" button
when calling the command, result: ERROR
In the same cad session as in step 5, add the DLL to the ""support file search path", editing the field by clicking the "Browse" button
when calling the command, result: ERROR
In the same cad session as in step 6, I call the NETLOAD command (filedia=1), navigate to the DLL folder, DO NOT SELECT ANYTHING AND CLICK CANCEL
when calling the command, result: WORKS
I close cad, open it again, set FILEDIA=0
when calling the command, result: ERROR
In the same cad session of step 8, NETLOAD, I inform the full path of the DLL
when calling the command, result: ERROR
In the same cad session as in step 9, FILEDIA=1, NETLOAD, I navigate to the folder, but I don't select anything, as in step 7,
when calling the command, result: WORKS
So it concludes that the NETLOAD command doesn't just do an "Assembly.LoadFrom".
And the fact that it works with FILEDIA=1, makes me believe that it is the part of the code that shows the NETLOAD window that somehow makes the DLL, or its types
visible and the System.IO.FileNotFoundException error does not occur
I added the code so you can look.
If you can help me, thank you
"MyCustomActivity.vb"
Imports System.Activities
Imports System.Activities.Presentation
Imports System.ComponentModel
Imports System.Drawing
Imports System.Windows
Imports System.Windows.Media
Imports System.Windows.Media.Imaging
<ToolboxBitmap(GetType(MyCustomActivity), "arc.png"), Designer(GetType(MyCustomDesigner))>
Public Class MyCustomActivity
Inherits CodeActivity
Protected Overrides Sub Execute(context As CodeActivityContext)
'faz alguma coisa
End Sub
End Class
Public NotInheritable Class MyCustomDesigner
Inherits MyActivityDesigner
Public Sub New()
MyBase.New(GetType(MyCustomActivity))
End Sub
End Class
Public MustInherit Class MyActivityDesigner
Inherits ActivityDesigner
Public Sub New(customActivityType As Type)
Dim toolAttrib As ToolboxBitmapAttribute = customActivityType.GetCustomAttributes(GetType(ToolboxBitmapAttribute), True)(0)
Using bitmap As New Bitmap(toolAttrib.GetImage(customActivityType))
Dim ImageDrawing As New ImageDrawing(System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bitmap.GetHbitmap,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions),
New Rect(0, 0, 16, 16))
Me.Icon = New DrawingBrush(ImageDrawing)
End Using
End Sub
End Class
"TestClass.VB"
Imports System.Reflection
Imports Microsoft.Win32
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.DatabaseServices
Imports System.IO
Public NotInheritable Class TesteClass
'precisa ser public, senao IExtensionApplication nao funciona
Implements IExtensionApplication
Public Shared ReadOnly PRODUCTKEY As String = HostApplicationServices.Current.UserRegistryProductRootKey
Public Shared ReadOnly LOADER As String = Reflection.Assembly.GetExecutingAssembly.Location
Public Shared ReadOnly PASTA As String = New FileInfo(LOADER).DirectoryName
Public Sub Initialize() Implements IExtensionApplication.Initialize
Try
Dim cUserApp = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(PRODUCTKEY & "\Applications", True)
With cUserApp.CreateSubKey(My.Application.Info.Title)
.SetValue("DESCRIPTION", My.Application.Info.Description)
.SetValue("MANAGED", 1, RegistryValueKind.DWord)
.SetValue("LOADCTRLS", 2, RegistryValueKind.DWord)
.SetValue("LOADER", System.Reflection.Assembly.GetExecutingAssembly.Location)
Try
.DeleteSubKey("Commands")
Catch
End Try
With .CreateSubKey("Commands")
For Each tp As Type In Assembly.GetExecutingAssembly.GetExportedTypes()
For Each meth As MethodInfo In tp.GetMethods()
For Each obj As CommandMethodAttribute In meth.GetCustomAttributes(GetType(CommandMethodAttribute), True)
.SetValue(obj.GlobalName, obj.GlobalName)
Next
Next
Next
End With
End With
Catch
End Try
End Sub
Public Sub Terminate() Implements IExtensionApplication.Terminate
End Sub
<CommandMethod("teste")>
Public Sub teste()
Dim f As New Form1
f.ShowDialog()
End Sub
End Class
"Form1.vb"
Imports System.Activities
Imports System.Activities.Core.Presentation
Imports System.Activities.Presentation
Imports System.Activities.Presentation.Toolbox
Imports System.Activities.Statements
Imports System.Windows
Imports System.Windows.Forms
Public Class Form1
Private Shared _firsload As Boolean = True
Public Sub New()
Dim dd As New DesignerMetadata()
dd.Register()
' Esta chamada é requerida pelo designer.
InitializeComponent()
' Adicione qualquer inicialização após a chamada InitializeComponent().
Dim WorkflowDesigner As New WorkflowDesigner
Dim ActivityBuilder As New ActivityBuilder With {.Implementation = New Flowchart}
WorkflowDesigner.Load(ActivityBuilder)
Dim ctrl As New ToolboxControl()
'Dim item As New ToolboxItemWrapper("TesteCAD.MyCustomActivity", TesteClass.LOADER, "", "teste")
Dim item As New ToolboxItemWrapper(GetType(MyCustomActivity), "teste")
ctrl.Categories.Add(New ToolboxCategory("teste") From {item})
ElementHost1.Child = ctrl
ElementHost2.Child = WorkflowDesigner.View
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim wd As New WorkflowDesigner
Using lixo As New Form With {.Size = New System.Drawing.Size(1, 1), .ShowInTaskbar = False, .FormBorderStyle = FormBorderStyle.None}
Dim elementHost As New Integration.ElementHost
lixo.Controls.Add(elementHost)
elementHost.Child = wd.View
AddHandler lixo.Activated, Sub()
Forms.Application.DoEvents()
lixo.Close()
End Sub
lixo.ShowDialog()
End Using
End Sub
End Class
"Form1.Designer.vb"
Imports System.Windows.Forms
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
Partial Class Form1
Inherits System.Windows.Forms.Form
'Descartar substituições de formulário para limpar a lista de componentes.
<System.Diagnostics.DebuggerNonUserCode()> _
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Try
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
Finally
MyBase.Dispose(disposing)
End Try
End Sub
'Exigido pelo Windows Form Designer
Private components As System.ComponentModel.IContainer
'OBSERVAÇÃO: o procedimento a seguir é exigido pelo Windows Form Designer
'Pode ser modificado usando o Windows Form Designer.
'Não o modifique usando o editor de códigos.
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
Me.SplitContainer1 = New System.Windows.Forms.SplitContainer()
Me.ElementHost1 = New System.Windows.Forms.Integration.ElementHost()
Me.ElementHost2 = New System.Windows.Forms.Integration.ElementHost()
CType(Me.SplitContainer1, System.ComponentModel.ISupportInitialize).BeginInit()
Me.SplitContainer1.Panel1.SuspendLayout()
Me.SplitContainer1.Panel2.SuspendLayout()
Me.SplitContainer1.SuspendLayout()
Me.SuspendLayout()
'
'SplitContainer1
'
Me.SplitContainer1.Dock = System.Windows.Forms.DockStyle.Fill
Me.SplitContainer1.Location = New System.Drawing.Point(0, 0)
Me.SplitContainer1.Name = "SplitContainer1"
'
'SplitContainer1.Panel1
'
Me.SplitContainer1.Panel1.Controls.Add(Me.ElementHost1)
'
'SplitContainer1.Panel2
'
Me.SplitContainer1.Panel2.Controls.Add(Me.ElementHost2)
Me.SplitContainer1.Size = New System.Drawing.Size(800, 450)
Me.SplitContainer1.SplitterDistance = 266
Me.SplitContainer1.TabIndex = 0
'
'ElementHost1
'
Me.ElementHost1.Dock = System.Windows.Forms.DockStyle.Fill
Me.ElementHost1.Location = New System.Drawing.Point(0, 0)
Me.ElementHost1.Name = "ElementHost1"
Me.ElementHost1.Size = New System.Drawing.Size(266, 450)
Me.ElementHost1.TabIndex = 0
Me.ElementHost1.Text = "ElementHost1"
Me.ElementHost1.Child = Nothing
'
'ElementHost2
'
Me.ElementHost2.Dock = System.Windows.Forms.DockStyle.Fill
Me.ElementHost2.Location = New System.Drawing.Point(0, 0)
Me.ElementHost2.Name = "ElementHost2"
Me.ElementHost2.Size = New System.Drawing.Size(530, 450)
Me.ElementHost2.TabIndex = 0
Me.ElementHost2.Text = "ElementHost2"
Me.ElementHost2.Child = Nothing
'
'Form1
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(800, 450)
Me.Controls.Add(Me.SplitContainer1)
Me.Name = "Form1"
Me.Text = "Form1"
Me.SplitContainer1.Panel1.ResumeLayout(False)
Me.SplitContainer1.Panel2.ResumeLayout(False)
CType(Me.SplitContainer1, System.ComponentModel.ISupportInitialize).EndInit()
Me.SplitContainer1.ResumeLayout(False)
Me.ResumeLayout(False)
End Sub
Friend WithEvents SplitContainer1 As SplitContainer
Friend WithEvents ElementHost1 As Integration.ElementHost
Friend WithEvents ElementHost2 As Integration.ElementHost
End Class
I found a solution by adding an AssemblyResolve event to the current AppDomain:
Private Shared Function MyHandler(ByVal source As Object, ByVal e As ResolveEventArgs) As Assembly
Return If(e.Name = GetType(TesteClass).Assembly.FullName, Assembly.LoadFile(LOADER), Nothing)
End Function
And I added the following line in 'Initialize':
AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf MyHandler
Worked perfectly!!!

Hide form's DoubleBuffered property without make it nonfunctional

Using a Class I am trying to hide the DoubleBuffered property from form's property window but without make it nonfunctional. So I did something like this in code example below... Ηowever, DoubleBuffered property still appears. So, can we really hide DoubleBuffered property and if yes, how can we do that?
Imports System.ComponentModel
Imports System.ComponentModel.Design
Public Class MyForm
Inherits Form
<Browsable(False)>
Public Overloads Property DoubleBuffered As Boolean
Get
Return MyBase.DoubleBuffered
End Get
Set(ByVal value As Boolean)
MyBase.DoubleBuffered = value
End Set
End Property
Public Sub New()
Me.DoubleBuffered = True
End Sub
End Class
You could create a custom component designer for your Form, but that is a daunting task to just recreate the functionality of the inaccessible System.Windows.Forms.Design.FormDocumentDesigner. The simpler way is use the Form's Site property as I have shown you before to access the designer services.
In this case, you need to override the ITypeDescriptorFilterService service of the designer host. This service is used by the designer for all type discovery/filtering operations and is not limited to a specific component.
The first step is to create a class that implements ITypeDescriptorFilterService. The following is one such implementation. It is a generic implementation that allows it to filter components of the specified type and takes list of property names that you want to exclude from the PropertyGrid display. The final item it requires is a reference to the existing service used by the designer host.
Friend Class FilterService(Of T) : Implements ITypeDescriptorFilterService
Private namesOfPropertiesToRemove As String()
Public Sub New(baseService As ITypeDescriptorFilterService, ParamArray NamesOfPropertiesToRemove As String())
Me.BaseService = baseService
Me.namesOfPropertiesToRemove = NamesOfPropertiesToRemove
End Sub
Public ReadOnly Property BaseService As ITypeDescriptorFilterService
Public Function FilterAttributes(component As IComponent, attributes As IDictionary) As Boolean Implements ITypeDescriptorFilterService.FilterAttributes
Return BaseService.FilterAttributes(component, attributes)
End Function
Public Function FilterEvents(component As IComponent, events As IDictionary) As Boolean Implements ITypeDescriptorFilterService.FilterEvents
Return BaseService.FilterEvents(component, events)
End Function
Public Function FilterProperties(component As IComponent, properties As IDictionary) As Boolean Implements ITypeDescriptorFilterService.FilterProperties
' ref: ITypeDescriptorFilterService Interface: https://msdn.microsoft.com/en-us/library/system.componentmodel.design.itypedescriptorfilterservice(v=vs.110).aspx
'
' The return value of FilterProperties determines if this set of properties is fixed.
' If this method returns true, the TypeDescriptor for this component can cache the
' results. This cache is maintained until either the component is garbage collected or the Refresh method of the type descriptor is called.
' allow other filters 1st chance to modify the properties collection
Dim ret As Boolean = BaseService.FilterProperties(component, properties)
' only remove properties if component is of type T
If TypeOf component Is T AndAlso Not (properties.IsFixedSize Or properties.IsReadOnly) Then
For Each propName As String In namesOfPropertiesToRemove
' If the IDictionary object does not contain an element with the specified key,
' the IDictionary remains unchanged. No exception is thrown.
properties.Remove(propName)
Next
End If
Return ret
End Function
End Class
Example Usage in Form:
Imports System.ComponentModel
Imports System.ComponentModel.Design
Public Class TestForm : Inherits Form
Private host As IDesignerHost
Private altTypeDescriptorProvider As FilterService(Of TestForm)
' spelling and character casing of removedPropertyNames is critical
' it is a case-sensative lookup
Private Shared removedPropertyNames As String() = {"DoubleBuffered"}
Public Overrides Property Site As ISite
Get
Return MyBase.Site
End Get
Set(value As ISite)
If host IsNot Nothing Then
UnwireDesignerCode()
End If
MyBase.Site = value
If value IsNot Nothing Then
host = CType(Site.GetService(GetType(IDesignerHost)), IDesignerHost)
If host IsNot Nothing Then
If host.Loading Then
AddHandler host.LoadComplete, AddressOf HostLoaded
Else
WireUpDesignerCode()
End If
End If
End If
End Set
End Property
Private Sub HostLoaded(sender As Object, e As EventArgs)
RemoveHandler host.LoadComplete, AddressOf HostLoaded
WireUpDesignerCode()
End Sub
Private Sub WireUpDesignerCode()
AddFilter()
End Sub
Private Sub UnwireDesignerCode()
If host IsNot Nothing Then
RemoveFilter()
End If
host = Nothing
End Sub
Private Sub AddFilter()
Dim baseFilter As ITypeDescriptorFilterService = CType(host.GetService(GetType(ITypeDescriptorFilterService)), ITypeDescriptorFilterService)
If baseFilter IsNot Nothing Then
' remove existing filter service
host.RemoveService(GetType(ITypeDescriptorFilterService))
' create our replacement service and add it to the host's services
altTypeDescriptorProvider = New FilterService(Of TestForm)(baseFilter, removedPropertyNames)
host.AddService(GetType(ITypeDescriptorFilterService), altTypeDescriptorProvider)
TypeDescriptor.Refresh(Me.GetType) ' force a type description rescan
End If
End Sub
Private Sub RemoveFilter()
If altTypeDescriptorProvider IsNot Nothing Then
host.RemoveService(GetType(ITypeDescriptorFilterService))
host.AddService(GetType(ITypeDescriptorFilterService), altTypeDescriptorProvider.BaseService)
altTypeDescriptorProvider = Nothing
End If
End Sub
End Class
Now when you create a form that inherits from TestForm, the DoubleBuffered property will be excluded from the PropertyGrid display.

how to zoom in the image inside a scrollable panel in vb

I have a scrollable panel with an image/picture box inside.
I wanted to zoom in and zoom out the image without the buttons disappearing on the lower left of the panel. by the way, the image is in it's actual size.
If I make it a scrollable panel that can be zoomed in and out, will i still be able to get the coordinates of the image by not using the coordinates of the screen but the coordinates of the actual image?
Pls help me
I'm not sure what you mean by
zoom in and zoom out the image without the buttons disappearing
But you can use this control created by Bob Powell. His site seems to be offline now but I found this code:
Imports System
Imports System.Collections
Imports System.ComponentModel
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Windows.Forms
Namespace bobpowell.net
'/ <summary>
'/ ZoomPicBox does what it says on the wrapper.
'/ </summary>
'/ <remarks>
'/ PictureBox doesn't lend itself well to overriding. Why not start with something basic and do the job properly?
'/ </remarks>
Public Class ZoomPicBox
Inherits ScrollableControl
Private _image As Image
<Category("Appearance"), Description("The image to be displayed")> _
Public Property Image() As Image
Get
Return _image
End Get
Set
_image = value
UpdateScaleFactor()
Invalidate()
End Set
End Property
Private _zoom As Single = 1F
<Category("Appearance"), Description("The zoom factor. Less than 1 to reduce. More than 1 to magnify.")> _
Public Property Zoom() As Single
Get
Return _zoom
End Get
Set
If value < 0 OrElse value < 1E-05 Then
value = 1E-05F
End If
_zoom = value
UpdateScaleFactor()
Invalidate()
End Set
End Property
Private Sub UpdateScaleFactor()
If _image Is Nothing Then
Me.AutoScrollMargin = Me.Size
Else
Me.AutoScrollMinSize = New Size(CInt(Me._image.Width * _zoom + 0.5F), CInt(Me._image.Height * _zoom + 0.5F))
End If
End Sub 'UpdateScaleFactor
Private _interpolationMode As InterpolationMode = InterpolationMode.High
<Category("Appearance"), Description("The interpolation mode used to smooth the drawing")> _
Public Property InterpolationMode() As InterpolationMode
Get
Return _interpolationMode
End Get
Set
_interpolationMode = value
End Set
End Property
Protected Overrides Sub OnPaintBackground(pevent As PaintEventArgs)
End Sub 'OnPaintBackground
' do nothing.
Protected Overrides Sub OnPaint(e As PaintEventArgs)
'if no image, don't bother
If _image Is Nothing Then
MyBase.OnPaintBackground(e)
Return
End If
'Set up a zoom matrix
Dim mx As New Matrix(_zoom, 0, 0, _zoom, 0, 0)
mx.Translate(Me.AutoScrollPosition.X / _zoom, Me.AutoScrollPosition.Y / _zoom)
e.Graphics.Transform = mx
e.Graphics.InterpolationMode = _interpolationMode
e.Graphics.DrawImage(_image, New Rectangle(0, 0, Me._image.Width, Me._image.Height), 0, 0, _image.Width, _image.Height, GraphicsUnit.Pixel)
MyBase.OnPaint(e)
End Sub 'OnPaint
Public Sub New()
'Double buffer the control
Me.SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.UserPaint Or ControlStyles.ResizeRedraw Or ControlStyles.UserPaint Or ControlStyles.DoubleBuffer, True)
Me.AutoScroll = True
End Sub 'New
End Class 'ZoomPicBox
End Namespace 'bobpowell.net

Custom control collection - Adding items at design time?

I am trying to make a reusable control similar to an Outlook-style sidebar. I have a CustomPanel. I also have a CustomCollectionControl, that inherits from flow layout panel. At design time I would like to add (x) CustomPanels to my CustomCollectionControl, through the properties window.
When I try to add from the (Collection) list in the properties window, it will show up in the list, but it will not add it to the control that is on the form.
Here is my code so far.
Imports System.Collections
Imports System.ComponentModel
Imports System.Windows.Forms
Public Class CustomCollectionControl
Inherits FlowLayoutPanel
''' <summary>
''' Required designer variable.
''' </summary>
Private _mComponents As Container = Nothing
Private _mCustompanels As CustomPanelCollection
Public Sub New()
' This call is required by the Windows.Forms Form Designer.
InitializeComponent()
SetStyle(ControlStyles.DoubleBuffer, True)
SetStyle(ControlStyles.AllPaintingInWmPaint, True)
_mCustompanels = New CustomPanelCollection(Me)
Padding = New Padding(0)
End Sub
#Region "Component Designer generated code"
''' <summary>
''' Required method for Designer support - do not modify
''' the contents of this method with the code editor.
''' </summary>
Private Sub InitializeComponent()
_mComponents = New System.ComponentModel.Container()
End Sub
#End Region
<EditorBrowsable(EditorBrowsableState.Always)> _
<Browsable(True)> _
<DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
<Bindable(True)> _
Public Property CustomPanels() As CustomPanelCollection
Get
Return _mCustompanels
End Get
Set(value As CustomPanelCollection)
_mCustompanels = value
End Set
End Property
Protected Overrides Sub OnResize(e As EventArgs)
MyBase.OnResize(e)
End Sub
End Class
Public Class CustomPanelCollection
Inherits CollectionBase
Private _mControl As CustomCollectionControl
Private _mCustomCollectionControl As CustomCollectionControl
Friend Sub New(control As CustomCollectionControl)
_mCustomCollectionControl = control
End Sub
Default Public ReadOnly Property Item(index As Integer) As CustomPanel
Get
Return DirectCast(List(index), CustomPanel)
End Get
End Property
Public Function Contains(cPanel As CustomPanel) As Boolean
Return List.Contains(cPanel)
End Function
Public Function Add(cPanel As CustomPanel) As Integer
Dim i As Integer
i = List.Add(cPanel)
cPanel.Control = _mCustomCollectionControl
Return i
End Function
Public Sub Remove(cPanel As CustomPanel)
List.Remove(cPanel)
cPanel.Control = Nothing
End Sub
End Class
Public Class CustomPanel
Inherits Panel
Friend Control As CustomCollectionControl
Public Sub New()
' TODO Set Stuff!
Height = 100
BorderStyle = BorderStyle.FixedSingle
Margin = New Padding(0)
Padding = New Padding(0)
Dim cBtn As New Button
cBtn.Height = 30
Controls.Add(cBtn)
cBtn.Dock = DockStyle.Top
End Sub
End Class
I need to find out when a CustomPanel is added through the properties window during design time, how to update the control with the changes?
The basic problem is that in order for the flow-layout logic to work on your panels, they need to be in the base control's ControlCollection. If/When you expose this thru the properties IDE the standard collection editor allows any control to be added to it.
Your CustomPanels() property on the other hand, allows only CustomPanel controls but they get stored in a different collection, so they do not show up on the form.
The SmartTag action to only add CustomPanel is a very viable workaround if it adds to the Controls collection. I am not sure how many of the standard Panel properties you want them to be able to edit, and since there is no way to specify the child button properties, there doesnt seem much difference between the collection editor and the SmartTag. I assume this is because it is a work in progress and/or removed to post a minimal example.
Another way is to get rid if the extra collection and use a custom collection editor which will restrict the type of control to what you want. This is shown below.
Notes:
I changed the generic names to make it easier to read. CustomCollectionControl is now FlowLayoutPanelEx and CustomPanel is FlowPanel.
Your Buttons arent hooked up to anything, nor are they exposed, so I am not sure how you plan to use them.
Since all that the FlowPanel does is store that one button, why not omit it and just add buttons of a certain size?
There are several other issues with the code(e.g. CustomPanel/FlowPanel should implement IDisposable since it is creating stuff). These and other issues are ignored in order to focus on implementing a minimal custom collection editor.
FlowLayoutPanelEx and FlowPanel:
' collection editor will need this:
Imports System.ComponentModel.Design
Public Class FlowLayoutPanelEx
Inherits FlowLayoutPanel
Public Sub New()
' This call is required by the Windows.Forms Form Designer.
' {PL} - no, it is not
'InitializeComponent()
SetStyle(ControlStyles.DoubleBuffer, True)
SetStyle(ControlStyles.AllPaintingInWmPaint, True)
Padding = New Padding(0)
End Sub
<EditorBrowsable(EditorBrowsableState.Always),
Browsable(True),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
Bindable(True),
Editor(GetType(FlowPanelCollectionEditor),
GetType(System.Drawing.Design.UITypeEditor))>
Public Overloads Property Controls() As ControlCollection
Get
Return MyBase.Controls
End Get
Set(value As ControlCollection)
End Set
End Property
End Class
Public Class FlowPanel
Inherits Panel
' ToDo: implememt IDisposable
Private myBtn As Button
' allow user to specify the text for the child button
Public Property ButtonText As String
Get
If myBtn IsNot Nothing Then
Return myBtn.Text
Else
Return String.Empty
End If
End Get
Set(value As String)
myBtn.Text = value
End Set
End Property
Public Sub New()
' TODO Set Stuff!
Height = 100
BorderStyle = BorderStyle.FixedSingle
Margin = New Padding(0)
Padding = New Padding(0)
Height = 40
myBtn = New Button
myBtn.Height = 30
Controls.Add(myBtn)
myBtn.Dock = DockStyle.Top
End Sub
End Class
The way you have it, the user can change any FlowPanel property in the Collection Editor including those you have explicitly set. I dont know enough about what you ultimately want to do to offer alternatives other than it seems like perhaps the Panel is cosmetic and maybe a Button alone would suffice.
Note the additional Editor attribute on the Controls property. This tells VS to use that collection editor:
Public Class FlowPanelCollectionEditor
Inherits CollectionEditor
Public Sub New(t As Type)
MyBase.New(t)
End Sub
' *** Magic happens here: ***
' override the base class to SPECIFY the Type allowed
' rather than letting it derive the Types from the collection type
' which would allow any control to be added
Protected Overrides Function CreateNewItemTypes() As Type()
Dim ValidTypes As Type() = {GetType(FlowPanel)}
Return ValidTypes
End Function
Public Overrides Function EditValue(context As ITypeDescriptorContext,
provider As IServiceProvider,
value As Object) As Object
Return MyBase.EditValue(context, provider, value)
End Function
End Class
Results:
The collection editor adds only FlowPanels:
As you can see, the new ButtonText property can be set from the collection editor. When the controls are added to the Controls collection for use on the form, ButtonText shows on the buttons:
Note that the user can still drag a TextBox or whatever to your FlowLayoutPanelEx and it will accept it. This is another of those "other issues" mentioned above.
An article on CodeProject, Enhanced CollectionEditor Framework provides a fairly comprehensive overview of collections and custom collection editors.
It includes a custom collection editor framework but it wont handle this situation as is. If you remove NotOverridable from the CreateNewItemTypes method and recompile, you should be able to inherit from EnhancedCollectionEditor and use some of the other features it provides.
It is not really needed; as the code above shows there is not much involved in restricting the Type allowed. The article might be of value though as you modify and refine FlowPanel and the button into their final form. (Disclaimer: I wrote the article).
I am adding this here because I cannot do it in the comments because there is too much text and images. Also, maybe someone coming here from a search engine will be able to get an idea of what to do.
This is what I wanted to achieve with the control:
Closed
Open
And here is the edited code to allow the (flat style) buttons to be clicked and open the parent panel. This is a very crude method of doing it, but I put it together to check if it worked before I tied up too much time in it:
' collection editor will need this:
Imports System.ComponentModel.Design
Imports System.Windows.Forms
Imports System.ComponentModel
Imports System.Drawing
Public Class FlowLayoutPanelEx
Inherits FlowLayoutPanel
Public Sub New()
SetStyle(ControlStyles.DoubleBuffer, True)
SetStyle(ControlStyles.AllPaintingInWmPaint, True)
Padding = New Padding(0)
BackColor = Color.FromKnownColor(KnownColor.ControlDark)
End Sub
<EditorBrowsable(EditorBrowsableState.Always),
Browsable(True),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
Bindable(True),
Editor(GetType(FlowPanelCollectionEditor),
GetType(System.Drawing.Design.UITypeEditor))>
Public Overloads Property Controls() As ControlCollection
Get
Return MyBase.Controls
End Get
Set(value As ControlCollection)
End Set
End Property
End Class
Public Class HeaderButton
Inherits Button
Public Property BtnID As Integer
Public Property BtnColor As System.Drawing.Color
Public Event ButtonClicked(sender As HeaderButton, buttonID As Int32)
Private Sub clicked(sender As Object, e As EventArgs) Handles Me.Click
RaiseEvent ButtonClicked(Me, BtnID)
End Sub
End Class
Public Class FlowPanel
Inherits Panel
' ToDo: implememt IDisposable
Private myBtn As HeaderButton
' allow user to specify the text for the child button
Public Property ButtonText As String
Get
If myBtn IsNot Nothing Then
Return myBtn.Text
Else
Return String.Empty
End If
End Get
Set(value As String)
myBtn.Text = value
End Set
End Property
Public Sub New()
BorderStyle = BorderStyle.FixedSingle
Margin = New Padding(0)
Padding = New Padding(0)
Height = 32
BackColor = Color.FromKnownColor(KnownColor.Info)
myBtn = New HeaderButton
AddHandler myBtn.ButtonClicked, AddressOf Me.ItemButtonClicked
myBtn.Height = 30
myBtn.Margin = New Padding(0)
myBtn.Padding = New Padding(0)
myBtn.Dock = DockStyle.Top
myBtn.FlatStyle = FlatStyle.Flat
BackColor = Color.FromKnownColor(KnownColor.Control)
Controls.Add(myBtn)
End Sub
Public Sub ItemButtonClicked(ByVal btn As HeaderButton, ByVal buttonID As Int32)
If btn.Parent.Height = 32 Then
btn.Parent.Height = 200
Else : btn.Parent.Height = 32
End If
End Sub
End Class
Public Class FlowPanelCollectionEditor
Inherits CollectionEditor
Public Sub New(t As Type)
MyBase.New(t)
End Sub
' *** Magic happens here: ***
' override the base class to SPECIFY the Type allowed
' rather than letting it derive the Types from the collection type
' which would allow any control to be added
Protected Overrides Function CreateNewItemTypes() As Type()
Dim ValidTypes As Type() = {GetType(FlowPanel)}
Return ValidTypes
End Function
Public Overrides Function EditValue(context As ITypeDescriptorContext,
provider As IServiceProvider,
value As Object) As Object
Return MyBase.EditValue(context, provider, value)
End Function
End Class
There is so much more that I have to do, like displaying changes to the controls in the designer, implementing Idisposable, adding a collapsible button on the side, and passing the height value of the panel through the form so it will open the full height. I'm probably going to draw the buttons to get some effects that are not available with the standard button.

Highlighting around textboxes

I am trying to draw a highlighted border around a custom textbox control so that I can reuse the highlighting feature for each new program I create. My approach so far has been to override the paint event in the control library (dll) after the custom property I have created is set. The code for the control is below.
Imports System.Windows.Forms
Imports System.ComponentModel
Imports System.Drawing
Imports System.ComponentModel.Design
<ToolboxBitmap(GetType(Button))>
Public Class Textbox_Custom
Inherits System.Windows.Forms.TextBox
Public Event OnEnterKeyPress()
Public Event MissingInfo_Change As EventHandler
Dim iMissing_Info As Boolean
Dim iCharacterInput As Cinput
Public Property CharacterInput As Cinput
'<Browsable(True), DefaultValue("AllowAll")>
Get
Return Me.iCharacterInput
End Get
Set(ByVal value As Cinput)
Me.iCharacterInput = value
End Set
End Property
Public Property Missing_Info As Boolean
'<Browsable(True), DefaultValue(True)>
Get
Return iMissing_Info
End Get
Set(value As Boolean)
iMissing_Info = value
**MyBase.Refresh()**
End Set
End Property
Protected Overrides Sub OnKeyPress(e As KeyPressEventArgs)
MyBase.OnKeyPress(e)
If Asc(e.KeyChar) = 13 Then
RaiseEvent OnEnterKeyPress()
End If
Select Case Me.iCharacterInput
Case Cinput.CharactersOnly
If IsNumeric(e.KeyChar) Then
e.Handled = True
End If
Case Cinput.NumericOnly
If Not IsNumeric(e.KeyChar) And Asc(e.KeyChar) <> 8 Then
e.Handled = True
End If
End Select
End Sub
Protected Overrides Sub OnPaint(e As PaintEventArgs)
MyBase.OnPaint(e)
**If iMissing_Info = True Then**
Dim rect As New Rectangle(New Point(0, 0), New Size(Me.Size.Width + 2, Me.Size.Height + 2))
Dim pen As New Pen(Brushes.OrangeRed, 2)
e.Graphics.DrawRectangle(pen, rect)
e.Dispose()
End If
End Sub
End Class
Public Enum Cinput
AllowAll
NumericOnly
CharactersOnly
End Enum
While debugging I have set a breakpoint in the OnPaint override (lines **), but it never hits it. I then put a breakpoint in the Set section of the Missing_Info property where I am trying to invalidate the control to redraw. It does hit the MyBase.Refresh breakpoint so I don't understand what I've missed.
I realize there have been several other posts on this topic, but from what I can tell they seem to require putting panels behind the control. I feel like I should be able to include this action in a custom control and not have to code a new highlighting section for each new project. Thanks for any help in advance.
In the end I decided to just go with changing the control background to a semi-transparent red color which should be obvious enough for what I'm doing.