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;
Related
Almost everytime I close VisualStudio my custom ToggleControl changes it's properties (size, location, margin) so it moves around in Designer, and gets bigger and bigger...
As I checked now location was set to 32000;32000, margin to 3;69000;3;69000 and size also some big number.
What could be the issue with this? I can't really find anything.
On another Tabcontrol I have the same ToggleControl that works fine, I tried to copy it but result is same.
Edit: Added control code
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
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.
So I am trying to create an application to ease creation of pixel arts (school project), what I've done so far is draw a grid in a panel, next step would be to allow the user to click on a cell and have it painted, but I can't manage to make it work, here's the code I have:
Private Sub drawGrid(g As Graphics, rows As Integer, columns As Integer)
Dim originPoint As Point = New Point(10, 2)
Dim size As Size = New Size(64, 64)
Dim left As Integer = originPoint.X
Dim up As Integer = originPoint.Y
Dim right As Integer = originPoint.X + (columns * size.Width)
Dim down As Integer = originPoint.Y + (rows * size.Height)
For y As Integer = up To down + 1 Step size.Height
Dim pt1 As New Point(left, y)
Dim pt2 As New Point(right, y)
g.DrawLine(Pens.Black, pt1, pt2)
Next
For x As Integer = left To right + 1 Step size.Width
Dim pt1 As New Point(x, up)
Dim pt2 As New Point(x, down)
g.DrawLine(Pens.Black, pt1, pt2)
Next
End Sub
This draws a grid with the amount of columns and rows the user wants, but I've been struggling to allow painting
What I've been thinking is: dispose this code, and create a 'pixel' class, create the amount of 'pixel' objects based on user rows and columns, and draw each one individually, then just change each 'pixel's' color
This is a Grid class that allows setting the color of its cells.
The Grid cell are referenced using a List(Of List(Of Class)).
The Cell class Object contains is a simple Rectagle property that measures the size of the cell, and a Color property, which allows to set the color of the single cell:
Friend Class GridCell
Public Property Cell() As Rectangle
Public Property CellColor() As Color
End Class
You can define:
The size of the Grid → ColoredGrid.GridSize = new Size(...)
The number of Columns and Rows → ColoredGrid.GridColumnsRows = new Size(...)
The position of the Grid inside the Canvas → ColoredGrid.GridPosition = New Point(...)
The color of the Grid → ColoredGrid.GridColor = Color.Gray
The BackGround color of the cells → ColoredGrid.CellColor = Color.FromArgb(32, 32, 32)
The color of a selected cell → ColoredGrid.SelectedCellColor = Color.OrangeRed
The Grid class holds a reference to the control which will be used as the Canvas for the grid painting. This reference is set in the class contructor.
The Grid registers the Canvas control Paint() and MouseClick() events to respond to the related actions automatically.
When a Mouse Click is detected on the Canvas surface, the MouseEventArgs e.Location property reports the coordinates where the Click occurred.
To identify the Grid Cell where this action is performed, the GetUpdateCell() method inspects the List(Of List(Of GridCell)) using a simple LINQ SelectMany() and identified the Cell rectangle that contains the Mouse Click coordinates (expressed as a Point() value).
This identification is performed simply checking whether the Cell Rectangle.Contains(Point()).
When the cell is identified, the Canvas Invalidate() method is called, specifing the area to repaint.
This area corresponds to the Cell Rectangle, so only this section is repainted when a Cell is colored, to save resources and time.
To test it, create a Panel and a Button in a Form:
Imports System.Drawing
'This Grid object in defined at Form Class scope
Public ColoredGrid As ColorGrid
'Button used to trigger the Grid painting
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If ColoredGrid IsNot Nothing Then
ColoredGrid.Dispose()
End If
ColoredGrid = New ColorGrid(Panel1)
ColoredGrid.GridSize = New Size(300, 300)
ColoredGrid.GridColumnsRows = New Size(10, 10)
ColoredGrid.GridPosition = New Point(10, 10)
ColoredGrid.GridColor = Color.White
ColoredGrid.CellColor = Color.FromArgb(32, 32, 32)
ColoredGrid.SelectedCellColor = Color.OrangeRed
ColoredGrid.BuildGrid()
End Sub
This is a visual sample that shows how it works:
This is the main Grid class.
The ColorGrid Class supports IDisposable, because it registers the described events. These must be unregistered when the Class is not used anymore. Weird things can happen if you don't.
Public Class ColorGrid
Implements IDisposable
Private Grid As List(Of List(Of GridCell))
Private CurrentGridSize As New Size(100, 100)
Private GridColRows As New Size(10, 10)
Private CellSize As New Size(10, 10)
Private MouseCell As Point = Point.Empty
Private Canvas As Control = Nothing
Private UpdateCell As Boolean = False
Private NewGrid As Boolean = False
Public Sub New(DrawingControl As Control)
If DrawingControl IsNot Nothing Then
Me.Canvas = DrawingControl
AddHandler Me.Canvas.Paint, New PaintEventHandler(AddressOf Me.ControlPaint)
AddHandler Me.Canvas.MouseClick, New MouseEventHandler(AddressOf Me.MouseHandler)
Me.GridPosition = New Point(10, 10)
Me.CellColor = Color.FromArgb(32, 32, 32)
End If
End Sub
Public Property GridPosition() As Point
Public Property CellColor() As Color
Public Property SelectedCellColor() As Color
Public Property GridColor() As Color
Public Property GridSize() As Size
Get
Return Me.CurrentGridSize
End Get
Set(value As Size)
Me.CurrentGridSize = value
SetCellSize()
End Set
End Property
Public Property GridColumnsRows() As Size
Get
Return Me.GridColRows
End Get
Set(value As Size)
Me.GridColRows = value
SetCellSize()
End Set
End Property
Private Property RefreshCell() As GridCell
Friend Class GridCell
Public Property Cell() As Rectangle
Public Property CellColor() As Color
End Class
Private Sub SetCellSize()
Me.CellSize = New Size((Me.CurrentGridSize.Width \ Me.GridColRows.Width),
(Me.CurrentGridSize.Height \ Me.GridColRows.Height))
If Me.CellSize.Width < 4 Then Me.CellSize.Width = 4
If Me.CellSize.Height < 4 Then Me.CellSize.Height = 4
End Sub
Public Sub BuildGrid()
If Me.Canvas Is Nothing Then Return
Me.Grid = New List(Of List(Of GridCell))()
For row As Integer = 0 To GridColumnsRows.Height - 1
Dim RowCells As New List(Of GridCell)()
For col As Integer = 0 To GridColumnsRows.Width - 1
RowCells.Add(New GridCell() With {
.Cell = New Rectangle(New Point(Me.GridPosition.X + (col * Me.CellSize.Width),
Me.GridPosition.Y + (row * Me.CellSize.Height)),
Me.CellSize),
.CellColor = Me.CellColor})
Next
Me.Grid.Add(RowCells)
Next
Me.NewGrid = True
Me.Canvas.Invalidate()
End Sub
Private Sub ControlPaint(o As Object, e As PaintEventArgs)
If Me.NewGrid Then
e.Graphics.Clear(Me.Canvas.BackColor)
Me.NewGrid = False
End If
Me.Grid.
SelectMany(Function(rowcells) rowcells).
Select(Function(colcell)
If Me.UpdateCell Then
Using brush As New SolidBrush(Me.RefreshCell.CellColor)
e.Graphics.FillRectangle(brush, Me.RefreshCell.Cell.X + 1, Me.RefreshCell.Cell.Y + 1,
Me.RefreshCell.Cell.Width - 1, Me.RefreshCell.Cell.Height - 1)
End Using
Me.UpdateCell = False
Return Nothing
Else
Using pen As New Pen(Me.GridColor)
e.Graphics.DrawRectangle(pen, colcell.Cell)
End Using
Using brush As New SolidBrush(colcell.CellColor)
e.Graphics.FillRectangle(brush, colcell.Cell.X + 1, colcell.Cell.Y + 1,
colcell.Cell.Width - 1, colcell.Cell.Height - 1)
End Using
End If
Return colcell
End Function).TakeWhile(Function(colcell) colcell IsNot Nothing).ToList()
End Sub
Private Sub MouseHandler(o As Object, e As MouseEventArgs)
Me.RefreshCell = GetUpdateCell(e.Location)
Me.RefreshCell.CellColor = Me.SelectedCellColor
Dim CellColorArea As Rectangle = Me.RefreshCell.Cell
CellColorArea.Inflate(-1, -1)
Me.UpdateCell = True
Me.Canvas.Invalidate(CellColorArea)
End Sub
Private Function GetUpdateCell(CellPosition As Point) As GridCell
Return Me.Grid.
SelectMany(Function(rowcells) rowcells).
Select(Function(gridcell) gridcell).
Where(Function(gridcell) gridcell.Cell.Contains(CellPosition)).
First()
End Function
Public Sub Dispose() Implements IDisposable.Dispose
If Me.Canvas IsNot Nothing Then
RemoveHandler Me.Canvas.Paint, AddressOf Me.ControlPaint
RemoveHandler Me.Canvas.MouseClick, AddressOf Me.MouseHandler
Me.Grid = Nothing
End If
End Sub
End Class
i dont have much experience with Graphics class in winforms.
i am only in the sketching stage of it (also the code i have added).
my problem is that i am trying to create a panel: clockPanel with some graphics on it, no exception is thrown but the panel (as i can see in the UI) have no graphics on it. tryed to look for examples but i cant find mistakes or something i missed in my code. probably its an easy one for those of you that experienced with graphics.
thank you for your time an consideration.
VB CODE:
adding 'clockpanel' panel to other pannel ('secondaryPannel') via instance to GoalsClock class
Public Class ManagersTab
...
Public Sub BuiledDashBoard()
...
Dim p As GoalsClock = New GoalsClock(100, 100, 0.8)
p.Create()
p.clockPanel.Location = New Point(200, 100)
secondaryPannel.Controls.Add(p.clockPanel)
...
End Sub
...
End Class
Create() method is the most relevant part:
Class GoalsClock
Private Gclock As Graphics
Private clockWidth As Int16
Private clockHeight As Int16
Private xPos As Int16
Private yPos As Int16
Public clockPanel As Panel
Private panelColor As Color
Private PercentTextColor As Color
' rectangles to store squares
Protected OuterRect As Rectangle
Protected InnerRect As Rectangle
Protected InnerStringBrush As Brush
Protected InnerStringColor As Color
Protected InnerStringFontSize As Byte
' inner square
Private InnerSquarePen As Pen
Private InnerSquarePen_Color As Color
Private InnerSquarePen_Width As Byte
' outer square
Private OuterSquarePen As Pen
Private OuterSquarePen_Color As Color
Private OuterSquarePen_Width As Byte
Private _PercentOfGoals As Single ' to calculate the goals deg arc
Public Property PercentOfGoals() As Single
Get
Return _PercentOfGoals * 100
End Get
Private Set(ByVal value As Single)
If value <= 1.0F Then
_PercentOfGoals = value
Else
value = 0
End If
End Set
End Property
Sub New(ByVal clockWidth As Int16, ByVal clockHeight As Int16, ByVal GoalsPercent As Single)
Me.clockWidth = clockWidth
Me.clockHeight = clockHeight
PercentOfGoals = GoalsPercent
' values for test
xPos = 0
yPos = 0
InnerStringFontSize = 12
OuterSquarePen = New Pen(Color.Gray)
InnerSquarePen = New Pen(Color.Cyan)
OuterSquarePen_Width = 23
InnerSquarePen_Width = 15
End Sub
''' <summary>
'''
''' create graphics of the goals clock on clockPanel
''' </summary>
''' <remarks></remarks>
Public Sub Create()
' panel
clockPanel = New Panel()
clockPanel.Size = New Size(clockWidth, clockHeight)
clockPanel.BackColor = Color.Beige
Gclock = clockPanel.CreateGraphics()
' create outer rectangle
OuterRect = New Rectangle(xPos, yPos, clockWidth, clockHeight)
' create inner rectangle
Dim w, h, x, y As Integer
getInnerRectSizeAndLocation(w, h, x, y)
InnerRect = New Rectangle(x, y, w, h)
' draw goals string inside inner rect
InnerStringBrush = Brushes.Cyan
Gclock.DrawString(getPercentString(), New Font("ARIAL", InnerStringFontSize, FontStyle.Bold), InnerStringBrush, InnerRect)
' create outer square
OuterSquarePen = New Pen(OuterSquarePen_Color, OuterSquarePen_Width)
Gclock.DrawArc(OuterSquarePen, OuterRect, 1.0F, 360.0F)
' create inner square
InnerSquarePen = New Pen(InnerSquarePen_Color, InnerSquarePen_Width)
Dim sweepAngle As Short = getSweepAngleFromGoalsPercent()
Gclock.DrawArc(InnerSquarePen, OuterRect, -90.0F, sweepAngle)
End Sub
Private Sub getInnerRectSizeAndLocation(ByRef w As Integer, ByRef h As Integer, ByRef x As Integer, ByRef y As Integer)
' values for test
w = 40
h = 40
x = 64
y = 65
End Sub
Private Function getPercentString() As String
Return PercentOfGoals.ToString() & "%"
End Function
Private Function getSweepAngleFromGoalsPercent() As Single
' value for test
Return 0.0F
End Function
End Class
You must subscribe to the panel's Paint event and perform all drawing there. The AddHandler statement is used to dynamically subscribe to events.
The Graphics class will not store any information about what you draw, so when your panel is redrawn everything you previously drew will be gone unless you draw it again. This is where the Paint event comes into play: it will be raised every time your panel is redrawn, passing an instance of a Graphics class in its PaintEventArgs so you can draw your stuff onto the panel again.
Public Sub Create()
' panel
clockPanel = New Panel()
clockPanel.Size = New Size(clockWidth, clockHeight)
clockPanel.BackColor = Color.Beige
' subscribe to the panel's paint event
AddHandler clockPanel.Paint, AddressOf clockPanel_Paint
End Sub
Private Sub clockPanel_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs)
Dim Gclock As Graphics = e.Graphics 'Local variable only, as the Graphics object might change.
' create outer rectangle
OuterRect = New Rectangle(xPos, yPos, clockWidth, clockHeight)
' create inner rectangle
Dim w, h, x, y As Integer
getInnerRectSizeAndLocation(w, h, x, y)
InnerRect = New Rectangle(x, y, w, h)
' draw goals string inside inner rect
InnerStringBrush = Brushes.Cyan
Gclock.DrawString(getPercentString(), New Font("ARIAL", InnerStringFontSize, FontStyle.Bold), InnerStringBrush, InnerRect)
' create outer square
OuterSquarePen = New Pen(OuterSquarePen_Color, OuterSquarePen_Width)
Gclock.DrawArc(OuterSquarePen, OuterRect, 1.0F, 360.0F)
' create inner square
InnerSquarePen = New Pen(InnerSquarePen_Color, InnerSquarePen_Width)
Dim sweepAngle As Short = getSweepAngleFromGoalsPercent()
Gclock.DrawArc(InnerSquarePen, OuterRect, -90.0F, sweepAngle)
End Sub
As you also might've seen I am constantly redeclaring a new Gclock variable in the Paint event. This is because the Graphics instance used to draw your panel with might change, so you shouldn't store it any longer than the time the Paint event lasts (so I highly recommend you remove the declaration in the top of your class).
The Problem
I am trying to have the line draw to the cursors current position as it moves. I've tried adding the code below to the MouseMove event in the form; however, nothing changed. I have been able to successfully draw the line, but regardless of what I do I just can't seem to get the line to follow the mouse. Also, it would be nice to be able to achieve this with reliable code without using a timer (for resources sake), but whatever works, works.
Code
The program is simply a blank form. So far this is all I got for code (this is all of the code):
Public Class drawing
Public xpos = MousePosition.X
Public ypos = MousePosition.Y
Public Sub DrawLineFloat(ByVal e As PaintEventArgs)
' Create pen.
Dim blackPen As New Pen(Color.Black, 2)
' Create coordinates of points that define line.
Dim x1 As Single = xpos
Dim y1 As Single = ypos
Dim x2 As Single = 100
Dim y2 As Single = 100
' Draw line to screen.
e.Graphics.DrawLine(blackPen, x1, y1, x2, y2)
End Sub
Private Sub drawing_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
DrawLineFloat(e)
End Sub
End Class
As you can see, I tried to modify the code for the MouseMove event, but it failed (I'm just including it anyways so you can see the previous attempt). Thanks in advance for any help.
This will do what you need:
private Point? startPoint;
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (startPoint.HasValue)
{
Graphics g = e.Graphics;
using (Pen p = new Pen(Color.Black, 2f))
{
g.DrawLine(p, startPoint.Value, new Point(100, 100));
}
}
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
this.startPoint = e.Location;
this.Invalidate();
}
this refers to the Form instance.
Code translated to Vb.Net using http://converter.telerik.com/
Private startPoint As System.Nullable(Of Point)
Protected Overrides Sub OnPaint(e As PaintEventArgs)
MyBase.OnPaint(e)
If startPoint.HasValue Then
Dim g As Graphics = e.Graphics
Using p As New Pen(Color.Black, 2F)
g.DrawLine(p, startPoint.Value, New Point(100, 100))
End Using
End If
End Sub
Protected Overrides Sub OnMouseMove(e As MouseEventArgs)
MyBase.OnMouseMove(e)
Me.startPoint = e.Location
Me.Invalidate()
End Sub
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();
}
}
}