Listing 1: The WhiteBoard control with events
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Threading;
namespace CustomEvent
{
public delegate void LineEventHandler(Object sender, LineEventArgs e);
public delegate void ColumnEventHandler(Object sender, ColumnEventArgs e);
public class LineEventArgs: EventArgs
{
private int oldValue, newValue;
public LineEventArgs(int oldValue, int newValue)
{
this.oldValue = oldValue;
this.newValue = newValue;
}
public int NewLine
{
get
{
return newValue;
}
}
public int OldLine
{
get
{
return oldValue;
}
}
}
public class ColumnEventArgs: EventArgs
{
private int oldValue, newValue;
public ColumnEventArgs(int oldValue, int newValue)
{
this.oldValue = oldValue;
this.newValue = newValue;
}
public int NewColumn
{
get
{
return newValue;
}
}
public int OldColumn
{
get
{
return oldValue;
}
}
}
public class WhiteBoard: UserControl
{
public event LineEventHandler LineChanged;
protected virtual void OnLineChanged(LineEventArgs e)
{
LineChanged(this, e);
}
public event ColumnEventHandler ColumnChanged;
protected virtual void OnColumnChanged(ColumnEventArgs e)
{
ColumnChanged(this, e);
}
private int rowCount = 10;
private int columnCount = 10;
private char[,] board;
private int characterWidth = 10;
private int characterHeight = 14;
private int lineSpace = 3;
public Color foreColor = Color.Black;
private Thread caretThread;
private bool caretVisible = true;
private int caretX, caretY;
private int penWidth = 2;
private Pen pen;
private bool keystrokeProcessed;
public WhiteBoard()
{
board = new char[columnCount, rowCount];
//initialize characters
for (int i=0; i<columnCount; i++)
{
for (int j=0; j<rowCount; j++)
{
board[i, j] =' ';
}
}
pen = new Pen(foreColor, penWidth);
this.BackColor = Color.White;
this.KeyPress += new KeyPressEventHandler(KeyPressed);
caretThread = new Thread(new ThreadStart(ShowCaret));
caretThread.Start();
}
public int CaretX
{
get
{
return caretX;
}
set
{
int oldValue = caretX;
caretX = value;
if (oldValue != caretX)
OnColumnChanged(new ColumnEventArgs(oldValue, caretX));
}
}
public int CaretY
{
get
{
return caretY;
}
set
{
int oldValue = caretY;
caretY = value;
if (oldValue != caretY)
OnLineChanged(new LineEventArgs(oldValue, caretY));
}
}
void ShowCaret()
{
try
{
while (true)
{
this.Invalidate( new
Rectangle(CaretX * characterWidth, CaretY * (characterHeight + lineSpace),
CaretX * characterWidth + 2 * penWidth, (CaretY +1) * (characterHeight +
lineSpace)));
this.Update();
Thread.Sleep(350);
caretVisible = !caretVisible;
}
}
catch (Exception)
{
}
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics graphics = e.Graphics;
Font font = new Font("Courier new", characterWidth);
Brush brush = new SolidBrush(foreColor);
for (int i=0; i<rowCount; i++)
{
for (int j=0; j<columnCount; j++)
{
graphics.DrawString(board[i, j].ToString(), font, brush,
new Point(i*characterWidth, j*(lineSpace+characterHeight)));
}
}
//draw caret here;
if (caretVisible)
{
int x = CaretX * characterWidth;
int y = CaretY * (lineSpace + characterHeight);
graphics.DrawLine(pen, x, y, x, y + lineSpace + characterHeight);
}
}
private void KeyPressed(object sender, KeyPressEventArgs e)
{
if (!keystrokeProcessed)
{
char c = e.KeyChar;
int i = (int) c;
if (i==8)
{
if (CaretX==0)
{
CaretX = columnCount - 1;
if (CaretY==0)
CaretY = rowCount - 1;
else
CaretY--;
}
else
{
CaretX--;
}
board[CaretX, CaretY] = ' ';
}
else
{
board[CaretX, CaretY] = c;
if (CaretX==columnCount -1)
{
CaretX = 0;
if (CaretY==rowCount -1)
CaretY = 0;
else
CaretY++;
}
else
CaretX++;
}
this.Invalidate();
this.Update();
}
}
protected override bool ProcessDialogKey(Keys keyData)
{
keystrokeProcessed = true;
switch (keyData)
{
case Keys.Down:
if (CaretY==rowCount-1)
CaretY = 0;
else
CaretY++;
break;
case Keys.Up:
if (CaretY==0)
CaretY = rowCount - 1;
else
CaretY--;
break;
case Keys.Left:
if (CaretX==0)
{
CaretX = columnCount -1;
if (CaretY==0)
CaretY = rowCount - 1;
else
CaretY--;
}
else
CaretX--;
break;
case Keys.Right:
if (CaretX==columnCount-1)
{
CaretX = 0;
if (CaretY==rowCount-1)
CaretY = 0;
else
CaretY++;
}
else
CaretX++;
break;
case Keys.Control | Keys.R:
this.BackColor = Color.Red;
break;
case Keys.Control | Keys.G:
this.BackColor = Color.Green;
break;
case Keys.Control | Keys.B:
this.BackColor = Color.Blue;
break;
case Keys.Control | Keys.Alt | Keys.R:
foreColor = Color.Red;
break;
case Keys.Control | Keys.Alt | Keys.G:
foreColor = Color.Green;
break;
case Keys.Control | Keys.Alt | Keys.B:
foreColor = Color.Blue;
break;
case Keys.Escape:
this.BackColor = Color.White;
break;
case Keys.Alt | Keys.F4:
Application.Exit(); //uu... abrupt exit.
break;
case Keys.F1:
MessageBox.Show("Help is on the way", "Message from ProcessDialogKey");
break;
default:
if ((int)(Keys.Control & keyData) != 0)
{
//The control key is pressed. Do something here if you want.
return true;
}
else if ((int)(Keys.Alt & keyData) != 0)
{
//The Alt key is pressed. Do something here if you want.
return true;
}
else
{
keystrokeProcessed = false; // let KeyPress event handler handle this keystroke.
}
break;
}
this.Invalidate();
this.Update();
return base.ProcessDialogKey(keyData);
}
protected override void Dispose(bool disposing)
{
if (disposing) {
caretThread.Abort();
}
base.Dispose(disposing);
}
}
}