VB.Net How to programmatically add a control and an event handler - vb.net

I'm creating a game using the PictureBox control and adding a MouseDown event to handle reducing the "health" value of the PictureBox.
I would like to programmatically add a new control when the initial control loses all of it's health so that I can add variance to how the new PictureBox appears, but I do not know how to add an event handler to a programmatically created control.
Update: Thanks for the help!
This is how my finished code works, if you would like to do the same.
Public Class Form1
Private Sub NewBug()
Dim pbBug As New PictureBox With {
.Name = "pb",
.Width = 100,
.Height = 100,
.Top = 75,
.Left = 75,
.SizeMode = PictureBoxSizeMode.Zoom,
.Image = My.Resources.bug}
Me.Controls.Add(pbBug)
AddHandler pbBug.MouseDown, Sub(sender As Object, e As EventArgs)
MessageBox.Show("Hello", "It Worked")
End Sub
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
NewBug()
End Sub
Thanks,
sunnyCr

Something isnt adding up. It would appear as though Dim MyButton As New Button() should be declared at Class scope, you should not have to declare WithEvents on local variables. Furthermore the MyButton_Click sub wouldnt compile if MyButton was Local to load routine. If it is declared at Class Scope then instead of Dim MyButton As New Button You would WithEvents MyButton As New Button If you want to keep it local then you could do something like this instead
Dim MyButton As New Button With {
.Name = "MyButton",
.Top = 100,
.Left = 100,
.Image = My.Resources.SomeImage}
Controls.Add(MyButton)
AddHandler MyButton.Click, Sub(s As Object, ev As EventArgs)
'Do stuff
End Sub
which is generally how I do things as this, unless I intend to remove the handler, then I will create a Sub and use AddressOf such as how you are attempting to use it.

You must create a class for generate a picturebox by code importing windows.system.Forms; as example you can do this, changing label for picturebox:
This is the class:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
class Etiqueta
{
private Label etiquetaHija;
public Label EtiquetaHija { get => etiquetaHija; set => etiquetaHija = value; }
public Etiqueta(Point posicion, Size dimensiones, string texto)
{
etiquetaHija = new Label();
etiquetaHija.Size = dimensiones;
etiquetaHija.Location = posicion;
etiquetaHija.Text = texto;
etiquetaHija.Click += EtiquetaHija_Click;
}
private void EtiquetaHija_Click(object sender, EventArgs e)
{
MessageBox.Show("Etiqueta Hija");
}
}
This is the code behind of the form:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Etiqueta etiqueta = new Etiqueta(new Point(20, 20), new Size(100, 100), "Ejemplo de creacion de un label por codigo con manejador de eventos");
this.Controls.Add(etiqueta.EtiquetaHija );
}
}
}

Related

problem with textbox TextChanged inside userControl (C# code to vb.net)

I'm trying to create a custom textbox with a userControl, my problem lies in the part of setting the default event of the userControl to handle the textChanged of the textbox. I currently have the userControl with only one textbox.
In c # I have this code that works perfectly (UserControl3.cs file):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace custom_controls
{
[DefaultEvent("_TextChanged")]
public partial class UserControl3 : UserControl
{
public UserControl3()
{
InitializeComponent();
}
public event EventHandler _TextChanged;
private void TextBox1_TextChanged(object sender, EventArgs e)
{
if (_TextChanged != null)
{
_TextChanged.Invoke(sender, e);
}
}
}
}
But I have not been able to translate it correctly to vb.net where I need the control. Any help or suggestion is greatly appreciated.
This is the code resulting from the conversion from C # to VB.net:
<DefaultEvent("_TextChanged")>
Public Class UserControl3
Public Event _TextChanged As EventHandler
Private Sub textBox1_TextChanged(sender As Object, e As EventArgs) Handles textBox1.TextChanged
If _TextChanged IsNot Nothing Then 'error here: _TextChanged
_TextChanged.Invoke(sender, e) 'error here: _TextChanged
End If
End Sub
End Class
Error image:
You can't raise events the same way in vb and c#. vb has a keyword RaiseEvent to do that
<DefaultEvent("_TextChanged")>
Public Class UserControl3
Public Event _TextChanged As EventHandler
Private Sub textBox1_TextChanged(sender As Object, e As EventArgs) Handles textBox1.TextChanged
RaiseEvent _TextChanged(sender, e)
End Sub
End Class

Problem with focusing on WebBrowser control when pressing TAB key

I'm making a Windows Forms application with VB.Net, Visual Studio 2015.
The Form has a WebBrowser control and other controls.
Whenever pressing the TAB key on keyboard, it always focuses on a html element loaded in the WebBrowser control first. Then pressing the TAB key again, the focus is switched between the HTML elements in the WebBrowser control.
Till ending up switching in all HTML elements, the focus doesn't switch to other controls in the Form.
Though I set .TabIndex = 1000 and .TabStop = false in the WebBrowser control, it always focuses on a html element loaded in the WebBrowser control first, always first.
So, I want to disable focusing on the WebBrowser control by pressing the TAB key or to disable the TAB key function in the Form entirely.
I have to get the answer done in VB.NET soon, but for now here's the C# version of it:
First, an extended web browser control, that you'll have to use on the form, with a custom event when the tab key is pressed.
Here we call the TabStop = false to ensure this key gets processed. Similar reasoning on WebBrowserShortcutsEnabled.
Then, we capture on the HTML Body, the key press event.
If the key code is a 9 (tab), we fire our event.
public class WebBrowserExtended : System.Windows.Forms.WebBrowser
{
protected virtual void OnTabKeyEvent(EventArgs e)
{
EventHandler handler = TabKeyEvent;
if (handler != null)
{
handler(this, e);
}
}
public event EventHandler TabKeyEvent;
public WebBrowserExtended() : base()
{
this.TabStop = false;
this.WebBrowserShortcutsEnabled = false;
}
protected override void OnDocumentCompleted(WebBrowserDocumentCompletedEventArgs e)
{
base.OnDocumentCompleted(e);
if (this.Document.Body != null)
this.Document.Body.KeyDown += new HtmlElementEventHandler(Body_KeyDown);
}
private void Body_KeyDown(Object sender, HtmlElementEventArgs e)
{
if (e.KeyPressedCode == 9 && !e.CtrlKeyPressed)
{
this.OnTabKeyEvent(e);
e.BubbleEvent = false;
}
}
}
And here's is your event handler:
private void webBrowser1_TabKeyEvent(object sender, EventArgs e)
{
var controls = new List<Control>(this.Controls.Cast<Control>());
var nextControl = controls.Where(c => c.TabIndex > webBrowser1.TabIndex).OrderBy(c => c.TabIndex).FirstOrDefault();
if (nextControl != null)
nextControl.Focus();
else
controls.OrderBy(c => c.TabIndex).FirstOrDefault().Focus();
}
And here's the VB version of the control:
Public Class WebBrowserExtended
Inherits System.Windows.Forms.WebBrowser
Protected Overridable Sub OnTabKeyEvent(ByVal e As EventArgs)
RaiseEvent TabKeyEvent(Me, e)
End Sub
Public Event TabKeyEvent As EventHandler
Public Sub New()
MyBase.New()
Me.TabStop = False
Me.WebBrowserShortcutsEnabled = False
End Sub
Protected Overrides Sub OnDocumentCompleted(ByVal e As WebBrowserDocumentCompletedEventArgs)
MyBase.OnDocumentCompleted(e)
If Me.Document.Body IsNot Nothing Then
AddHandler Me.Document.Body.KeyDown, AddressOf Body_KeyDown
End If
End Sub
Private Sub Body_KeyDown(ByVal sender As Object, ByVal e As HtmlElementEventArgs)
If e.KeyPressedCode = 9 AndAlso Not e.CtrlKeyPressed Then
Me.OnTabKeyEvent(e)
e.BubbleEvent = False
End If
End Sub
End Class
And the VB event handler:
Private Sub WebBrowser1_TabKeyEvent(sender As Object, e As EventArgs) Handles WebBrowser1.TabKeyEvent
Dim controls = New List(Of Control)(Me.Controls.Cast(Of Control))
Dim nextControl = controls.Where(Function(c)
Return c.TabIndex > WebBrowser1.TabIndex
End Function).OrderBy(Function(c)
Return c.TabIndex
End Function).FirstOrDefault()
If Not controls Is Nothing Then
nextControl.Focus()
Else
controls.OrderBy(Function(c)
Return c.TabIndex
End Function).FirstOrDefault().Focus()
End If
End Sub

Append text to a RichTextBox from another class in VB.NET

I have a Form (ClientGUI) that has a RichTextBox. What I want to do is to append text to this RichTextBox from a Sub located in another class (MyQuickFixApp). I know that the Sub works, because the debugger go through, but it doesn't append the text to my RichTextBox.
How do I do that ?
Thanks for you help !
ClientGUI.vb :
Imports QuickFix
Imports QuickFix.Transport
Imports QuickFix.Fields
Public Class ClientGUI
Dim initiator As SocketInitiator
Public Sub ClientGUI_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim filename As String = "Resources/initiator.cfg"
Dim settings As New SessionSettings(filename)
Dim myApp As New MyQuickFixApp()
Dim storeFactory As New FileStoreFactory(settings)
Dim logFactory As New FileLogFactory(settings)
initiator = New SocketInitiator(myApp, storeFactory, settings, logFactory)
End Sub
Public Sub ConnectToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ConnectToolStripMenuItem.Click
ToolStripDropDownButton1.Text = "Establishing connection..."
ToolStripDropDownButton1.Image = My.Resources.Connecting
initiator.Start()
End Sub
Public Sub DisconnectToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles DisconnectToolStripMenuItem.Click
ToolStripDropDownButton1.Text = "Disconnecting..."
ToolStripDropDownButton1.Image = My.Resources.Disconnecting
initiator.Stop()
End Sub
End Class
MyQuickFixApp.vb :
Imports QuickFix
Imports QuickFix.Transport
Imports QuickFix.Fields
Public Class MyQuickFixApp
Inherits MessageCracker : Implements IApplication
Dim _session As Session = Nothing
Public Sub FromAdmin(message As Message, sessionID As SessionID) Implements IApplication.FromAdmin
ClientGUI.RichTextBox1.AppendText("")
ClientGUI.RichTextBox1.AppendText("IN (ADMIN): " + message.ToString())
Try
Crack(message, sessionID)
Catch ex As Exception
ClientGUI.RichTextBox1.AppendText("")
ClientGUI.RichTextBox1.AppendText("==Cracker exception==")
ClientGUI.RichTextBox1.AppendText(ex.ToString())
ClientGUI.RichTextBox1.AppendText(ex.StackTrace)
End Try
End Sub
Public Sub FromApp(message As Message, sessionID As SessionID) Implements IApplication.FromApp
ClientGUI.RichTextBox1.AppendText("")
ClientGUI.RichTextBox1.AppendText("IN (APP): " + message.ToString())
Try
Crack(message, sessionID)
Catch ex As Exception
ClientGUI.RichTextBox1.AppendText("")
ClientGUI.RichTextBox1.AppendText("==Cracker exception==")
ClientGUI.RichTextBox1.AppendText(ex.ToString())
ClientGUI.RichTextBox1.AppendText(ex.StackTrace)
End Try
End Sub
Public Sub ToApp(message As Message, sessionId As SessionID) Implements IApplication.ToApp
Try
Dim possDupFlag As Boolean = False
If (message.Header.IsSetField(Tags.PossDupFlag)) Then
possDupFlag = Converters.BoolConverter.Convert(message.Header.GetField(Tags.PossDupFlag))
End If
If (possDupFlag) Then
Throw New DoNotSend()
End If
Catch ex As FieldNotFoundException
ClientGUI.RichTextBox1.AppendText("OUT (APP): " + message.ToString())
End Try
End Sub
Public Sub OnCreate(sessionID As SessionID) Implements IApplication.OnCreate
'_session = Session.LookupSession(sessionID)
ClientGUI.RichTextBox1.AppendText("Session created - " + sessionID.ToString())
End Sub
Public Sub OnLogon(sessionID As SessionID) Implements IApplication.OnLogon
ClientGUI.RichTextBox1.AppendText("Logon - " + sessionID.ToString())
ClientGUI.ToolStripDropDownButton1.Text = "Connected"
ClientGUI.ToolStripDropDownButton1.Image = My.Resources.Connected
'MsgBox("onlogon")
End Sub
Public Sub OnLogout(sessionID As SessionID) Implements IApplication.OnLogout
ClientGUI.RichTextBox1.AppendText("Logout - " + sessionID.ToString())
ClientGUI.ToolStripDropDownButton1.Text = "Disconnected"
ClientGUI.ToolStripDropDownButton1.Image = My.Resources.Disconnected
End Sub
Public Sub ToAdmin(message As Message, sessionID As SessionID) Implements IApplication.ToAdmin
ClientGUI.RichTextBox1.AppendText("OUT (ADMIN): " + message.ToString())
End Sub
Public Sub OnMessage(message As FIX42.Heartbeat, sessionID As SessionID)
ClientGUI.RichTextBox1.AppendText("HEARTBEAT")
End Sub
End Class
I guess that the code in MyQuickFixApp class access to the default instance of your ClientGUI, not the instance which is actually running, each time you write ClientGUI.(...).
See this thread Why is there a default instance of every form in VB.Net but not in C#? for more information about default instance, which is something you should avoid to use.
So you could add a parameter in the MyQuickFixApp class constructor :
Public Class MyQuickFixApp
Inherits MessageCracker : Implements IApplication
Dim _clientGUI As ClientGUI = Nothing
Public Sub New(cltGui As ClientGUI)
_clientGUI = cltGui
End sub
(...)
End class
Then, replace in the MyQuickFixApp class all the ClientGUI.(...), with _clientGUI.(...) to be sure to access to the correct instance.
And finally, initialize your MyQuickFixApp class in ClientGUI like this:
Dim myApp As New MyQuickFixApp(me)
Note that this code, you can only access to the method of the class in the Form_Load event. This variable should be declared in the class and initialized in the form_load if you want to access it later from the ClientGUI form.
Public Class ClientGUI
Dim initiator As SocketInitiator
Dim myApp As MyQuickFixApp()
Public Sub ClientGUI_Load(sender As Object, e As EventArgs) Handles MyBase.Load
(...)
myApp =New MyQuickFixApp(Me)
(...)
End Sub
(...)
End Class
In Form
private void button3_Click(object sender, EventArgs e)
{
TestClass tc = new TestClass();
tc.addComment(richTextBox1);
}
In Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
public class TestClass
{
public void addComment(RichTextBox rt)
{
rt.Text = rt.Text + Environment.NewLine + "My Dynamic Text";
}
}
you can do it same in VB.net also

listbox item forecolor change

Does anyone know why the Listbox1.Refresh() command may not trigger the ListBox1_DrawItem sub every time?
In Microsoft Visual Basic 2010, a listbox has a forcolor and backcolor property. These properties change the forcolour and backcolor for all the items in the listbox. By default there is no property for the forecolor and backcolor of an individual item on a listbox, I am aware there is on a list view but I would still wish to use a listbox.
I am trying to have the ability to change the forecolor and backcolor properties of individual items in the listbox.
To do this the listbox's draw item sub must be used with the listbox's drawmode property set to OwnerDrawFixed. Then using a brush colour along with the e.graphics the forecolor or backcolor can be changed.
I have seen and followed examples of how to do this for the currently selected item. Such as the one from ehow's website.
What I am tiring to do however is change the colour of the litsbox item as it is added depending on a variable.
Here is my code:
Private Sub listbox_add()
Me.ListBox1.Items.Add(listbox_text(list_num)) ' adds the line to the list box
add_item_colour = True
ListBox1.Refresh()
End Sub
Private Sub ListBox1_DrawItem(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawItemEventArgs) Handles ListBox1.DrawItem
Dim myBrush As Brush = Brushes.Black
e.DrawBackground()
If add_item_colour = True Then
If blue_message = True Then
myBrush = Brushes.Blue
Else
myBrush = Brushes.Black
End If
e.Graphics.DrawString(ListBox1.Items.Item(list_num), ListBox1.Font, myBrush, _
New RectangleF(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height))
add_item_colour = False
End If
e.DrawFocusRectangle()
End Sub
The listbox_text is a string array that stores the string being added, the list_num is a integer that increments when new items are added to the listbox and the blue_message is a Boolean that it true when I want a blue message and false when I don't.
The problem I seem to be having is that Listbox1.Refresh() command does not seem to be triggering the ListBox1_DrawItem sub every time it is called. I found this by using brake points. Does anyone know why this might be the case and how I could fix it?
Thanks, any help on this would be much appreciated.
First of all I suggest you to use background worker instead of directly writing down your code on UI thread.
Please refer the code below:
public partial class Form1 : Form
{
Brush myBrush = Brushes.Blue;
public Form1()
{
InitializeComponent();
this.backgroundWorker1.DoWork += backgroundWorker1_DoWork;
this.backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
this.backgroundWorker1.RunWorkerAsync(this);
}
private void listBox1_DrawItem(object sender, DrawItemEventArgs e)
{
e.DrawBackground();
e.Graphics.DrawString(listBox1.Items[e.Index].ToString(), listBox1.Font, myBrush, new RectangleF(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height));
e.DrawFocusRectangle();
}
private void button1_Click(object sender, EventArgs e)
{
this.backgroundWorker1.RunWorkerAsync(button1);
}
private void button2_Click(object sender, EventArgs e)
{
this.backgroundWorker1.RunWorkerAsync(button2);
}
void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.listBox1.Refresh();
}
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
if (e.Argument == this)
{
listBox1.Items.Add("p1");
listBox1.Items.Add("p2");
}
else if (e.Argument == this.button1)
{
myBrush = Brushes.Red;
listBox1.Refresh();
}
else if (e.Argument == this.button2)
{
myBrush = Brushes.Green;
if (listBox1.SelectedItem == null)
return;
var test = listBox1.Items[listBox1.SelectedIndex];
listBox1.SelectedItem = test;
var g = listBox1.CreateGraphics();
var rect = listBox1.GetItemRectangle(listBox1.SelectedIndex);
listBox1_DrawItem(listBox1, new DrawItemEventArgs(g, this.Font, rect, listBox1.SelectedIndex, DrawItemState.Default));
listBox1.Refresh();
}
}
}

Toggle Button Control

Can I change my button control to toggle-button?
Is there any simple way to change the button property to make it toggle button?
According to this post on OSIX all you need to do is use a CheckBox but set it's appearance to Button.
In code:
CheckBox checkBox1 = new System.Windows.Forms.CheckBox();
checkBox1.Appearance = System.Windows.Forms.Appearance.Button;
(C# code but you see how it works).
But you can do this from the Properties dialog in the designer.
To Change Checkbox to Simple Latching On/Off Button
myCheckBox.Appearance = System.Windows.Forms.Appearance.Button
To Add Custom Toggle (Sliding) On/Off Switch
Right click project in VS and select 'Add' then 'User Control...'
Name your new file "Toggle.vb"
Paste the code below
Switch to your form and drag your 'toggle' control from toolbox to form
Size & settings can be changed like standard control
Colors can be changed in OnPaint method of Toggle Class
VB.net
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Windows.Forms
Public Class Toggle
Inherits System.Windows.Forms.UserControl
Private _checked As Boolean
Public Property Checked As Boolean
Get
Return _checked
End Get
Set(ByVal value As Boolean)
If Not _checked.Equals(value) Then
_checked = value
Me.OnCheckedChanged()
End If
End Set
End Property
Protected Overridable Sub OnCheckedChanged()
RaiseEvent CheckedChanged(Me, EventArgs.Empty)
End Sub
Public Event CheckedChanged(ByVal sender As Object, ByVal e As EventArgs)
Protected Overrides Sub OnMouseClick(e As MouseEventArgs)
Me.Checked = Not Me.Checked
Me.Invalidate()
MyBase.OnMouseClick(e)
End Sub
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
Me.OnPaintBackground(e)
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias
Using path = New GraphicsPath()
Dim d = Padding.All
Dim r = Me.Height - 2 * d
path.AddArc(d, d, r, r, 90, 180)
path.AddArc(Me.Width - r - d, d, r, r, -90, 180)
path.CloseFigure()
e.Graphics.FillPath(If(Checked, Brushes.DarkGray, Brushes.LightGray), path)
r = Height - 1
Dim rect = If(Checked, New System.Drawing.Rectangle(Width - r - 1, 0, r, r), New System.Drawing.Rectangle(0, 0, r, r))
e.Graphics.FillEllipse(If(Checked, Brushes.Green, Brushes.LightSlateGray), rect)
End Using
End Sub
End Class
C#
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace Your_Project_Name
{
class Toggle : CheckBox
{
public Toggle()
{
SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
Padding = new Padding(6);
}
protected override void OnPaint(PaintEventArgs e)
{
this.OnPaintBackground(e);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
using (var path = new GraphicsPath())
{
var d = Padding.All;
var r = this.Height - 2 * d;
path.AddArc(d, d, r, r, 90, 180);
path.AddArc(this.Width - r - d, d, r, r, -90, 180);
path.CloseFigure();
e.Graphics.FillPath(Checked ? Brushes.DarkGray : Brushes.LightGray, path);
r = Height - 1;
var rect = Checked ? new System.Drawing.Rectangle(Width - r - 1, 0, r, r)
: new System.Drawing.Rectangle(0, 0, r, r);
e.Graphics.FillEllipse(Checked ? Brushes.Green : Brushes.LightSlateGray, rect);
}
}
}
}
This code is from several sources over the years and has some minor tweaks. It appears it exist in various forms on different sites so it's unclear who to attribute
All code was tested in Visual Studio 2017
If i understood correctly, you can achieve this functionality by using a flag. For example:
bool isClicked = false;
and in the clicked event to put the following code to invert the bool:
isClicked = !isClicked;