Resize ToolStrip Button Image programatically at startup via toolstrip.ImageScalingSize - vb.net

So I've read around this and will provide relevant properties at the end.
I'm looking to store a custom ToolStrip button image size in my.settings and load them at startup, changing them to a user set size.. The code I run at startup is:
Dim tss As New List(Of ToolStrip)
tss = GetAllControls(Me).OfType(Of ToolStrip)().ToList
For Each ts In tss
ts.BackColor = My.Settings.ToolStripBGColor
ts.ImageScalingSize = New Size(My.Settings.ToolStripImgScalingSize, My.Settings.ToolStripImgScalingSize)
ts.ResumeLayout()
ts.Invalidate()
ts.Refresh()
Next
ToolStripContainer.Invalidate()
ToolStripContainer.Refresh()
This does change the properties of all of the ToolStips. However, the images initially display at the default 16x16 UNTIL I drag them into another area of the ToolStripContainer. It then resizes correctly. This tends to imply to me that it's something to so with the draw of these containers/controls (hence the blanket bombing of .invalidate, .resumelayout and .refresh!)
Regarding proprieties, the relevant ones within designer view:
ToolStripButton
.autosize = true
.imagescaling = SizeToFit
ToolStrip
.autosize = true
.imagesclaing = 16,16 (later modified by code)
ToolStripContainer
couldn't see any that would effect this!??
This is one of those where you go round in circles for half a day over what essentially could be due to a janky aspect of .net! Could be me though...

Getting this to work with AutoSize=True is always a bit confusing. I've found that if you set it to False with layout suspended and then set it to True with layout enabled, that you can get the desired effect.
That description is probably clear as mud, so here is the code pattern.
With ToolStrip1
.SuspendLayout()
.AutoSize = False
.ImageScalingSize = New Size(40, 40)
.ResumeLayout()
.AutoSize = True
End With

Imports System.Drawing : Imports Microsoft.VisualBasic
Imports Microsoft.Win32 : Imports System
Imports System.IO : Imports System.Windows.Forms
Public Class Form1
Inherits Form
Private toolStripItem1 As ToolStripButton
Private toolStrip1 As ToolStrip
Public Sub New()
toolStrip1 = New System.Windows.Forms.ToolStrip()
toolStrip1.Size = New System.Drawing.Size(580,40)
toolStrip1.BackColor = System.Drawing.Color.MistyRose
toolStrip1.AutoSize = True
toolStripItem1 = New System.Windows.Forms.ToolStripButton()
toolStrip1.SuspendLayout()
Me.SuspendLayout()
toolStrip1.Items.AddRange(New System.Windows.Forms.ToolStripButton() _
{toolStripItem1})
toolStrip1.Location = New System.Drawing.Point(0, 0)
toolStrip1.Name = "toolStrip1"
toolStripItem1.AutoSize = False
toolStripItem1.Size = New System.Drawing.Size(110,95)
toolStripItem1.BackgroundImage = Image.FromFile("D:\Book4\Resources\icos\CUT.png")
toolStripItem1.Name = "toolStripItem1"
toolStripItem1.Text = "Cut"
toolStripItem1.Font = New System.Drawing.Font("Segoe UI", 16.0!, _
System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, _
CType(0, Byte))
toolStripItem1.TextAlign = System.Drawing.ContentAlignment.TopCenter
AddHandler Me.toolStripItem1.Click, New System.EventHandler _
(AddressOf Me.toolStripItem1_Click)
Me.AutoScaleDimensions = New System.Drawing.SizeF(6F, 13F)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(1500,900)
Me.BackColor = ColorTranslator.FromHtml("#808080")
Me.Controls.Add(Me.toolStrip1)
Me.Name = "Form1"
toolStrip1.ResumeLayout(False)
Me.ResumeLayout(False)
Me.PerformLayout()
End Sub
Public Sub Form1_Loaded(sender As Object, e As EventArgs) _
Handles MyBase.Load
Try
Dim ico As New System.Drawing.Icon("D:\Resources\icos\kvr.ico")
Me.Icon = ico
Catch ex As Exception
End Try
End Sub
Public Shared Sub Main()
Dim form1 As Form1 = New Form1()
form1.ShowDialog()
End Sub
Private Sub toolStripItem1_Click(ByVal sender As Object,ByVal e As EventArgs)
System.Windows.Forms.MessageBox.Show("Successfully enlarged ToolStripButtonImage size")
End Sub
End Class

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!!!

Fire Timer Tick from Baseform

I have a base Form with a Timer that simply should show the time in all Forms that inherit from it.
MainForm (which inherits from BaseForm) does this job very well.
From MainForm, I open other Forms which inherit from Baseform.
In these Forms, the time won't change after the Form is opened.
The work is the same in all derived Forms. Each Timer Tick should update the Time in a Label in the active Form.
I have tried Property Binding and adding the event in each form. Nothing works properly.
I am thankful for any hint :-)
Here i have the code from my BaseForm
Partial Class FrmBasisNew
Inherits Form
<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
'Wird vom Windows Form-Designer benötigt.
Private components As System.ComponentModel.IContainer
'Hinweis: Die folgende Prozedur ist für den Windows Form-Designer erforderlich.
'Das Bearbeiten ist mit dem Windows Form-Designer möglich.
'Das Bearbeiten mit dem Code-Editor ist nicht möglich.
<System.Diagnostics.DebuggerStepThrough()>
Private Sub InitializeComponent()
Me.components = New System.ComponentModel.Container()
Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(FrmBasisNew))
Me.Tim_Uhrzeit = New System.Windows.Forms.Timer(Me.components)
Me.PNLTOP = New System.Windows.Forms.Panel()
Me.lblTime = New System.Windows.Forms.Label()
Me.PNLTOP.SuspendLayout()
Me.SuspendLayout()
'
'Tim_Uhrzeit
'
Me.Tim_Uhrzeit.Interval = 1000
'
'PNLTOP
'
Me.PNLTOP.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink
Me.PNLTOP.BackColor = Global.KundF.My.MySettings.Default.glUserDefinedBackColor
Me.PNLTOP.Controls.Add(Me.lblTime)
Me.PNLTOP.Dock = System.Windows.Forms.DockStyle.Top
Me.PNLTOP.Location = New System.Drawing.Point(0, 0)
Me.PNLTOP.Margin = New System.Windows.Forms.Padding(0)
Me.PNLTOP.Name = "PNLTOP"
Me.PNLTOP.Size = New System.Drawing.Size(788, 58)
Me.PNLTOP.TabIndex = 2
'
'lblTime
'
Me.lblTime.DataBindings.Add(New System.Windows.Forms.Binding("Text", Global.KundF.My.MySettings.Default, "glUserdefinedTime", True, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged))
Me.lblTime.Dock = System.Windows.Forms.DockStyle.Right
Me.lblTime.Font = New System.Drawing.Font("Microsoft Sans Serif", 15.75!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
Me.lblTime.ForeColor = System.Drawing.SystemColors.ActiveCaptionText
Me.lblTime.Location = New System.Drawing.Point(724, 0)
Me.lblTime.Name = "lblTime"
Me.lblTime.Size = New System.Drawing.Size(64, 58)
Me.lblTime.TabIndex = 6
Me.lblTime.Text = Global.KundF.My.MySettings.Default.glUserdefinedTime
'
'FrmBasisNew
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(788, 716)
Me.ControlBox = False
Me.Controls.Add(Me.PNLTOP)
Me.MaximizeBox = False
Me.MinimizeBox = False
Me.Name = "FrmBasisNew"
Me.ShowIcon = False
Me.ShowInTaskbar = False
Me.WindowState = System.Windows.Forms.FormWindowState.Maximized
Me.PNLTOP.ResumeLayout(False)
Me.ResumeLayout(False)
End Sub
Friend WithEvents PNLTOP As Panel
Protected WithEvents Tim_Uhrzeit As Timer
Friend WithEvents lblTime As Label
End Class
Then the Code for The BaseForm
Public Class FrmBasisNew
Private Sub Tim_Uhrzeit_Tick(sender As Object, e As EventArgs) Handles Tim_Uhrzeit.Tick
SetTime()
End Sub
Public Overridable Sub SetTime()
Me.lblTime.Text = Format(Now, "hh:mm:ss").ToString
End Sub
End Class
Now, the DesignerCode for my Mainform

add button to TreeNode

Good day.
There is a custom control that adds a button to each Node
Imports System.Windows.Forms.VisualStyles
Public Class CustomTreeView
Inherits TreeView
Private buttonRect As New Rectangle(80, 2, 50, 26)
Private ReadOnly stringFormat As StringFormat
Public Sub New()
SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
DrawMode = TreeViewDrawMode.OwnerDrawText
ShowLines = False
FullRowSelect = True
ItemHeight = 30
stringFormat = New StringFormat With {
.Alignment = StringAlignment.Near,
.LineAlignment = StringAlignment.Center
}
End Sub
Protected Overrides Sub OnDrawNode(ByVal e As DrawTreeNodeEventArgs)
e.Graphics.DrawString(e.Node.Text, Me.Font, New SolidBrush(Me.ForeColor), e.Bounds, stringFormat)
ButtonRenderer.DrawButton(e.Graphics, New Rectangle(e.Node.Bounds.Location + New Size(buttonRect.Location), buttonRect.Size), "btn", Me.Font, True, If(e.Node.Tag IsNot Nothing, CType(e.Node.Tag, PushButtonState), PushButtonState.Normal))
End Sub
Protected Overrides Sub OnNodeMouseClick(ByVal e As TreeNodeMouseClickEventArgs)
Select Case e.Node.Tag
Case Nothing, Is <> PushButtonState.Pressed
Return
End Select
e.Node.Tag = PushButtonState.Normal
MessageBox.Show(e.Node.Text & " clicked")
' force redraw
e.Node.Text = e.Node.Text
End Sub
Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
Dim tnode As TreeNode = GetNodeAt(e.Location)
If tnode Is Nothing Then
Return
End If
Dim btnRectAbsolute As New Rectangle(tnode.Bounds.Location + New Size(buttonRect.Location), buttonRect.Size)
If btnRectAbsolute.Contains(e.Location) Then
tnode.Tag = PushButtonState.Pressed
tnode.Text = tnode.Text
End If
End Sub
End Class
tell me how you can display the button only to the first (main) nod?
And how, when you click on this button, not display a message, but let's say call some procedure?
There is no built-in button tree node. But you can create a custom tree node having a button yourself. This custom tree node inherits from TreeNode. To improve extensibility, we declare an interface for tree nodes having a DrawNode method:
Imports System.Windows.Forms.VisualStyles
Public Interface ICustomDrawTreeNode
Sub DrawNode(ByVal e As DrawTreeNodeEventArgs, buttonState As PushButtonState)
End Interface
We also create a module containing some settings used in the custom tree view and in the custom tree node
Module Settings
Public ReadOnly ButtonRect As New Rectangle(80, 2, 50, 26)
Public ReadOnly TextStringFormat = New StringFormat() With {
.Alignment = StringAlignment.Near,
.LineAlignment = StringAlignment.Center,
.FormatFlags = StringFormatFlags.NoClip Or StringFormatFlags.FitBlackBox Or StringFormatFlags.LineLimit
}
End Module
We can then implement a button node like this
Imports System.Windows.Forms.VisualStyles
Public Class ButtonTreeNode
Inherits TreeNode
Implements ICustomDrawTreeNode
Private ReadOnly buttonText As String
Public Sub New(text As String, buttonText As String)
MyBase.New(text)
Me.buttonText = buttonText
End Sub
Public Sub DrawNode(e As DrawTreeNodeEventArgs, buttonState As PushButtonState) _
Implements ICustomDrawTreeNode.DrawNode
Dim font As Font = e.Node.TreeView.Font
' Draw Text to the left of the button
Dim rect As Rectangle = New Rectangle(
e.Node.Bounds.Location,
New Size(Settings.ButtonRect.Left, e.Bounds.Height))
e.Graphics.DrawString(e.Node.Text, font, Brushes.Black, rect, Settings.TextStringFormat)
' Draw the button
rect = New Rectangle(
e.Node.Bounds.Location + Settings.ButtonRect.Location,
Settings.ButtonRect.Size)
ButtonRenderer.DrawButton(e.Graphics, rect, buttonText, font, True, buttonState)
End Sub
End Class
It has a Private ReadOnly buttonText As String to store the text of the button. The normal node text and the button text are passed in the constructor of ButtonTreeNode:
Public Sub New(text As String, buttonText As String)
The DrawNode method will be called be the CustomTreeView in OnDrawNode.
In CustomTreeView I declared a NodeButtonClick event that will be raised when the button of a node is clicked. You can then handle this event in the form. When you select the CustomTreeView in the designer, this new event will appear in the "Action" section of the events.
Imports System.ComponentModel
Imports System.Windows.Forms.VisualStyles
Public Class CustomTreeView
Inherits TreeView
<Category("Action")>
Public Event NodeButtonClick(e As TreeNodeMouseClickEventArgs)
Private _isButtonPressed As Boolean
Public Sub New()
SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
DrawMode = TreeViewDrawMode.OwnerDrawText
ShowLines = False
FullRowSelect = True
ItemHeight = 30
End Sub
Protected Overrides Sub OnDrawNode(e As DrawTreeNodeEventArgs)
Dim customDrawNode As ICustomDrawTreeNode = TryCast(e.Node, ICustomDrawTreeNode)
If customDrawNode Is Nothing Then ' Normal text node.
e.Graphics.DrawString(e.Node.Text, Font, Brushes.Black, e.Node.Bounds, Settings.TextStringFormat)
Else
customDrawNode.DrawNode(e, If(_isButtonPressed, PushButtonState.Pressed, PushButtonState.Normal))
End If
End Sub
Protected Overrides Sub OnNodeMouseClick(e As TreeNodeMouseClickEventArgs)
If _isButtonPressed Then
_isButtonPressed = False
Refresh()
Dim buttonNode = TryCast(e.Node, ButtonTreeNode)
If buttonNode IsNot Nothing Then
RaiseEvent NodeButtonClick(e)
End If
End If
End Sub
Protected Overrides Sub OnMouseDown(e As MouseEventArgs)
Dim buttonNode = TryCast(GetNodeAt(e.Location), ButtonTreeNode)
If buttonNode IsNot Nothing Then
Dim btnRectAbsolute As New Rectangle(
buttonNode.Bounds.Location + Settings.ButtonRect.Location,
Settings.ButtonRect.Size)
_isButtonPressed = btnRectAbsolute.Contains(e.Location)
If _isButtonPressed Then
Refresh()
End If
End If
End Sub
End Class
In the form you can write
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
TreeView1.Nodes.Add("Text")
TreeView1.Nodes.Add(New ButtonTreeNode("Caption", "Button"))
End Sub
Private Sub TreeView1_NodeButtonClick(e As TreeNodeMouseClickEventArgs) _
Handles TreeView1.NodeButtonClick
MessageBox.Show(e.Node.Text & " clicked")
End Sub
End Class
This adds a normal text node and a custom button node to the TreeView. It also handles the NodeButtonClick of the custom TreeView.

Changing 'lamp' Colour Indicator within the Graphical User Interface (Visual Studio 2019)

I would like to change the colour within a single circular indicator within a Graphical User Interface, so that it shows when an action is completed or when it fails ['two tone green/red LED']. I've looked through the inbuilt presets within the Toolbox but have been unable find anything.
I would therefore be grateful for any assistance.
I've found this code on the msdn.microsoft.com forum, which changes the colour of the centre of the 'dot' when you press the RadioButton.
Private Sub RadioButton_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles RadioButton1.Paint, RadioButton2.Paint
If DirectCast(sender, RadioButton).Checked Then
e.Graphics.FillEllipse(Brushes.Red, New RectangleF(2.5, 4.7, 7.2, 7.2))
End If
So have incorporated it into my code, its not at all elegant and there is clearly room for improvement, but it does work.
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
If My.Computer.Network.Ping("192.168.0.1") Then
RadioButton1.ForeColor = Color.Green
RadioButton1.ForeColor = Color.Black
Else
RadioButton1.ForeColor = Color.Red
RadioButton1.ForeColor = Color.Black
End If
End Sub
Private Sub RadioButton_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles RadioButton1.Paint
If My.Computer.Network.Ping("192.168.0.1") Then
e.Graphics.FillEllipse(Brushes.Green, New RectangleF(2.5, 4.7, 7.2, 7.2))
Else
e.Graphics.FillEllipse(Brushes.Red, New RectangleF(2.5, 4.7, 7.2, 7.2))
End If
End Sub
Explanation: when the 'Test Network' button is pressed it sends out a network ping, and depending upon the return the Network RadioButton 'dot' changes colour to either Green or Red,
Here's ON/OFF LED control.
Add a new class to your project, name it say OnOffLed.vb, copy the code below and paste it in the new class.
Imports System.Windows.Forms
Imports System.Drawing
Imports System.Drawing.Drawing2D
Public Class OnOffLed
Inherits Panel
Public Enum LedState
[On]
Off
End Enum
Sub New()
SetStyle(ControlStyles.AllPaintingInWmPaint Or
ControlStyles.OptimizedDoubleBuffer Or
ControlStyles.ResizeRedraw Or
ControlStyles.UserPaint, True)
UpdateStyles()
End Sub
Private _state As LedState = LedState.Off
Public Property State As LedState
Get
Return _state
End Get
Set(value As LedState)
_state = value
Invalidate()
End Set
End Property
Private _onText As String
Public Property OnText As String
Get
Return _onText
End Get
Set(value As String)
_onText = value
Invalidate()
End Set
End Property
Private _offText As String
Public Property OffText As String
Get
Return _offText
End Get
Set(value As String)
_offText = value
Invalidate()
End Set
End Property
Protected Overrides Sub OnPaint(e As PaintEventArgs)
Dim rec As New Rectangle(2, 2, Height - 5, Height - 5)
Dim recText As New Rectangle(Height + 2, 1, Width - (Height - 2), Height)
Dim G As Graphics = e.Graphics
G.SmoothingMode = SmoothingMode.AntiAlias
G.Clear(Parent.BackColor)
If _state = LedState.On Then
Dim cb As New ColorBlend With {
.Colors = {Color.Green, Color.DarkGreen, Color.Green},
.Positions = {0, 0.5, 1}
}
Using lgb As New LinearGradientBrush(rec, Color.Empty, Color.Empty, 90.0F) With {.InterpolationColors = cb}
G.FillEllipse(lgb, rec)
End Using
Else
Dim cb As New ColorBlend With {
.Colors = {Color.Red, Color.DarkRed, Color.Red},
.Positions = {0, 0.5, 1}
}
Using lgb As New LinearGradientBrush(rec, Color.Empty, Color.Empty, 90.0F) With {.InterpolationColors = cb}
G.FillEllipse(lgb, rec)
End Using
End If
G.TextRenderingHint = Drawing.Text.TextRenderingHint.ClearTypeGridFit
Using br As New SolidBrush(ForeColor)
Using sf As New StringFormat With {.Alignment = StringAlignment.Near, .LineAlignment = StringAlignment.Center}
G.DrawString(If(_state = LedState.On, _onText, _offText), Font, br, recText, sf)
End Using
End Using
End Sub
End Class
Rebuild your project.
In the ToolBox under your project's component tab, you'll find the new control. OnOffLed. Drop it in your form as you drop any other control.
You can toggle the state through the State property, set different text if you need that for each state through the OnText and OffText properties.
Usage Example:
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
If My.Computer.Network.Ping("192.168.2.01") Then
OnOffLed1.State = OnOffLed.LedState.On
Else
OnOffLed1.State = OnOffLed.LedState.Off
End If
End Sub
Good luck.

Using IMAP in VB.Net to retrieve Mails from MS Exchange Server

I am referring to a previous post somewhere in the past (cf. Hyperlink). I could not add any comments, nor did I consider writing a reply since my Problem differs slightly. Please excuse if I posted in the wrong section or for opening a new thread on this topic, I am still new to this Forum.
Please let me illustrate the following issue: Similar to this post, I would like to access and retrieve emails and attachments from a MS Exchange Server. I mainly used the code provided by in the Hyperlink above, but I could not connect to the mail Server (I used port 587). In my opinion there was a successful Connection, but the code stops when reaching the following line
Dim Read_Stream2 = New StreamReader(Sstream)
Saying that the data stream could not be read.
I also have a question about this particular line, since I am unable to figure out why there is need to convert the NetworkStream into an SslStream and then into a StreamReader Object. Could somebody please explain this necessity?
As for the remaining Problem, please consider my code so far below. If it might be too cumbersome using IMAP, I would also welcome hints about how to achieve this goal using POP3.
Thanks a mil in advance for any help provided.
Imports System.Net.Sockets
Imports System.IO
Imports System.Text
Imports System.Net.Security
Public Class emailDownloader
Dim ServerNm As String
Dim UsrNm As String
Dim PassStr As String
Dim _IntPort As Integer
Dim ImapClient As New Net.Sockets.TcpClient
Dim NetworkS_stream As NetworkStream
Dim m_sslStream As SslStream
Dim Read_Stream As StreamReader
Dim StatResp As String
Dim m_buffer() As Byte
Function Login(ByVal Sstream As SslStream, ByVal Server_Command As String)
ImapClient = New TcpClient(ServerNm, _IntPort)
NetworkS_stream = ImapClient.GetStream 'Read the stream
Sstream = New SslStream(NetworkS_stream)
Dim Read_Stream2 = New StreamReader(Sstream)
Server_Command = Server_Command ' + vbCrLf
m_buffer = System.Text.Encoding.ASCII.GetBytes(Server_Command.ToCharArray())
Sstream.Write(m_buffer, 0, m_buffer.Length)
Dim Server_Reponse As String
Server_Reponse = Read_Stream2.ReadLine()
Return Server_Reponse
End Function
Private Sub btnStart_Click(sender As System.Object, e As System.EventArgs) Handles btnStart.Click
lbMailsRetrieved.Items.Clear()
ServerNm = tbServerName.Text
_IntPort = tbPortName.Text
UsrNm = tbUserName.Text
PassStr = tbPasswort.Text
StatResp = Login(m_sslStream, "LOGIN " + UsrNm + " " + PassStr + " ") & vbCrLf
lbMailsRetrieved.Items.Add(StatResp)
End Sub
End Class
There was a solution initially programmed in C#, which can be found here. I modified the code a bit and it is working for exchange (and only that).
Imports Microsoft.Exchange.WebServices.Data
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Data
Imports System.Drawing
Imports System.Linq
Imports System.Net.Sockets
Imports System.Text
Imports System.Threading.Tasks
Imports System.Windows.Forms
Namespace ReadMailFromExchangeServer
Public Class Form1
Inherits Form
Private exchange As ExchangeService
Public Sub New()
InitializeComponent()
lstMsg.Clear()
lstMsg.View = View.Details
lstMsg.Columns.Add("Date", 150)
lstMsg.Columns.Add("From", 250)
lstMsg.Columns.Add("Subject", 400)
lstMsg.Columns.Add("Has Attachment", 50)
lstMsg.Columns.Add("Id", 100)
lstMsg.FullRowSelect = True
End Sub
Private Sub btnRead_Click(sender As Object, e As EventArgs) Handles btnRead.Click
ConnectToExchangeServer()
'Dim ts As New TimeSpan(0, -1, 0, 0)
'Dim [date] As DateTime = DateTime.Now.Add(ts)
'Dim filter As New SearchFilter.IsGreaterThanOrEqualTo(ItemSchema.DateTimeReceived, [date])
If exchange IsNot Nothing Then
Dim findResults As FindItemsResults(Of Item) = exchange.FindItems(WellKnownFolderName.Inbox, New ItemView(50))
'Original
'Dim findResults As FindItemsResults(Of Item) = exchange.FindItems(WellKnownFolderName.Inbox, filter, New ItemView(50))
For Each item As Item In findResults
Dim message As EmailMessage = EmailMessage.Bind(exchange, item.Id)
Dim listItem As New ListViewItem({message.DateTimeReceived.ToString(), _
message.From.Name.ToString() + _
"(" + message.From.Address.ToString() + ")", _
message.Subject, (If((message.HasAttachments), "Yes", "No")), _
message.Id.ToString()})
lstMsg.Items.Add(listItem)
Next
If findResults.Items.Count <= 0 Then
lstMsg.Items.Add("No Messages found!!")
End If
End If
End Sub
Public Sub ConnectToExchangeServer()
lblMsg.Text = "Connecting to Exchange Server.."
lblMsg.Refresh()
Try
exchange = New ExchangeService(ExchangeVersion.Exchange2007_SP1)
exchange.Credentials = New WebCredentials("abc", "xyz")
exchange.AutodiscoverUrl("efg")
lblMsg.Text = "Connected to Exchange Server : " + exchange.Url.Host
lblMsg.Refresh()
Catch ex As Exception
lblMsg.Text = "Error Connecting to Exchange Server!!" + ex.Message
lblMsg.Refresh()
End Try
End Sub
Private Sub btnLoadAttachment_Click(sender As Object, e As EventArgs) Handles btnLoadAttachment.Click
If exchange IsNot Nothing Then
If lstMsg.Items.Count > 0 Then
Dim item As ListViewItem = lstMsg.SelectedItems(0)
If item IsNot Nothing Then
Dim msgid As String = item.SubItems(4).Text.ToString()
Dim message As EmailMessage = EmailMessage.Bind(exchange, New ItemId(msgid))
If message.HasAttachments AndAlso TypeOf message.Attachments(0) Is FileAttachment Then
Dim fileAttachment As FileAttachment = TryCast(message.Attachments(0), FileAttachment)
'Change the below Path   
fileAttachment.Load("C:[my_path]" + fileAttachment.Name)
lblAttach.Text = "Attachment Downloaded : " + fileAttachment.Name
Else
MessageBox.Show("No Attachments found!!")
End If
Else
MessageBox.Show("Please select a Message!!")
End If
Else
MessageBox.Show("Messages not loaded!!")
End If
Else
MessageBox.Show("Not Connected to Mail Server!!")
End If
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs)
End Sub
Private Sub InitializeComponent()
Me.btnRead = New System.Windows.Forms.Button()
Me.lstMsg = New System.Windows.Forms.ListView()
Me.btnLoadAttachment = New System.Windows.Forms.Button()
Me.lblMsg = New System.Windows.Forms.Label()
Me.label1 = New System.Windows.Forms.Label()
Me.lblAttach = New System.Windows.Forms.Label()
Me.SuspendLayout()
'
'btnRead
'
Me.btnRead.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None
Me.btnRead.FlatStyle = System.Windows.Forms.FlatStyle.Flat
Me.btnRead.Location = New System.Drawing.Point(39, 284)
Me.btnRead.Name = "btnRead"
Me.btnRead.Size = New System.Drawing.Size(174, 23)
Me.btnRead.TabIndex = 0
Me.btnRead.Text = "Read Mails"
Me.btnRead.UseVisualStyleBackColor = True
'
'lstMsg
'
Me.lstMsg.Location = New System.Drawing.Point(27, 70)
Me.lstMsg.Name = "lstMsg"
Me.lstMsg.Size = New System.Drawing.Size(664, 191)
Me.lstMsg.TabIndex = 1
Me.lstMsg.UseCompatibleStateImageBehavior = False
'
'btnLoadAttachment
'
Me.btnLoadAttachment.FlatStyle = System.Windows.Forms.FlatStyle.System
Me.btnLoadAttachment.Location = New System.Drawing.Point(517, 284)
Me.btnLoadAttachment.Name = "btnLoadAttachment"
Me.btnLoadAttachment.Size = New System.Drawing.Size(174, 23)
Me.btnLoadAttachment.TabIndex = 2
Me.btnLoadAttachment.Text = "Load Attachments"
Me.btnLoadAttachment.UseVisualStyleBackColor = True
'
'lblMsg
'
Me.lblMsg.AutoSize = True
Me.lblMsg.Location = New System.Drawing.Point(36, 361)
Me.lblMsg.Name = "lblMsg"
Me.lblMsg.Size = New System.Drawing.Size(38, 13)
Me.lblMsg.TabIndex = 3
Me.lblMsg.Text = "Ready"
'
'label1
'
Me.label1.AutoSize = True
Me.label1.Location = New System.Drawing.Point(24, 54)
Me.label1.Name = "label1"
Me.label1.Size = New System.Drawing.Size(82, 13)
Me.label1.TabIndex = 4
Me.label1.Text = "Today's Messages"
'
'lblAttach
'
Me.lblAttach.AutoSize = True
Me.lblAttach.Location = New System.Drawing.Point(514, 361)
Me.lblAttach.Name = "lblAttach"
Me.lblAttach.Size = New System.Drawing.Size(148, 13)
Me.lblAttach.TabIndex = 5
Me.lblAttach.Text = "No attachmment downloaded"
'
'Form1
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(812, 591)
Me.Controls.Add(Me.lblAttach)
Me.Controls.Add(Me.label1)
Me.Controls.Add(Me.lblMsg)
Me.Controls.Add(Me.btnLoadAttachment)
Me.Controls.Add(Me.lstMsg)
Me.Controls.Add(Me.btnRead)
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)
Me.PerformLayout()
End Sub
Friend WithEvents btnRead As System.Windows.Forms.Button
Friend WithEvents lstMsg As System.Windows.Forms.ListView
Friend WithEvents btnLoadAttachment As System.Windows.Forms.Button
Friend WithEvents lblMsg As System.Windows.Forms.Label
Friend WithEvents label1 As System.Windows.Forms.Label
Friend WithEvents lblAttach As System.Windows.Forms.Label
End Class
End Namespace
For the issue described in the beginning, the present code provides a solution. Thus I would like to mark this is an answer and close this thread (I know, usually one should not mark their very own answer as answer). Hope this approach is ok.