65.9K
CodeProject is changing. Read more.
Home

Creating a postit control in C# (.Net 3.5)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.50/5 (5 votes)

Jul 30, 2012

CPOL

3 min read

viewsIcon

40746

downloadIcon

885

A postit control

Introduction

This tutorial describes an approach for creating a postit control in C# (.NET 3.5). It started when I was experimenting in Paint to draw a postit. At some point, I decided to make a control out of it. This could be used, for instance, in a virtual SCRUM-board or in a todo-application.

a simple postit

a postit with more text

multiple postits

Features 

Before I started, I defined a short list of features to implement. Other features will be certainly added in future versions.

Properties to set at creation:

  • Message: The message itself 
  • Font: The font type and size
  • TextColor: The text color of the message
  • PostitColor: The color of the postit
  • Urgency: A flag that indicates whether the task is urgent or not

Actions to perform on the postit:

  • Move: moving the postit around
  • Change size: making the postit larger or smaller with the mouse wheel
  • Reset size: Setting the postit to its original size

Using the code

This section first describes the implementation of the control and then the implementation of a sample client using the control.

Step 1: Create an image

After some experimentation, I created a bitmap that was good enough. You can of course use the image that is available in the attachments.

Step 2: Project creation

Create a project of type Windows Forms Application in Visual Studio.

Step 3: Add image as resource

  • Open the project properties and go to the Resources tab
  • Select Add Resource and then Add Existing File.
  • Select the bitmaps attached to this article (‘lightyellow.bmp’, ‘flatyellow.bmp’)

Step 4: Add user control

Add a new user control via the Solution Explorer and name it Postit.

Step 5: Implementing the control

The following properties are defined here: 

private string message;  // the message
private Size postitSize; // the size of the postit
private Bitmap postitBitMap; // the bitmap

private int sizeDiff = 20; // the diff for resizing the postit
private int maxWidth = 750; // the maximum width
private int maxHeigth = 750; // the maximum height
private int minWidth = 150; // the minimum width
private int minHeigth = 150; // the minimum width

private int blackBorderWidth = 50; // the width to avoid a black border around the bitmap
private int blackBorderHeight = 70; // the height to avoid a black border around the bitmap

private int messageLeft = 5; // the left position of the message
private int messageTop = 100; // the top position of the message

private bool isUrgent = false; // the urgency flag
private int urgencyFlagLeft = 5; // the left position of the urgency flag
private int urgencyFlagTop = 5; // the top position of the urgency flag

private Size originalSize; // the original size
private Font messageFont = new Font("Tahoma", 20); // the font
private Brush messageColor = Brushes.Black; // the font color
private PostitColor postitColor; // the color of the postit

The postit control has three different constructors:

public Postit(String message)
{
    this.message = message;
    this.postitColor = PostitColor.FlatYellow;
    this.init();
}

public Postit(String message, Font messageFont, Brush messageColor, PostitColor postitColor)
{              
    this.message = message;
    this.messageFont = messageFont;
    this.messageColor = messageColor;
    this.postitColor = postitColor;
    this.init();            
}

public Postit(String message, Font messageFont, Brush messageColor, PostitColor postitColor, bool isUrgent)
{            
    this.message = message;
    this.messageFont = messageFont;
    this.messageColor = messageColor;
    this.postitColor = postitColor;
    this.isUrgent = isUrgent;
    this.init();
}

All constructors call the init()-method, that does all the general initialization, i. e. it creates the bitmap, defines the size of the postit and the original size and sets the event handlers:

private void init()
{
    //set the control styles
    SetStyle(ControlStyles.OptimizedDoubleBuffer | 
        ControlStyles.UserPaint | 
        ControlStyles.OptimizedDoubleBuffer, true);
    
    InitializeComponent();
    
    // set the postit bitmap
     if (this.postitColor == PostitColor.LightYellow)
         this.postitBitMap = PostitDemo.Properties.Resources.lightyellow;
     else
         this.postitBitMap = PostitDemo.Properties.Resources.flatyellow;
                
    //set the size
    this.postitSize = this.postitBitMap.Size;
    this.originalSize = this.Size;                        
                
    // set the event handlers
    this.MouseWheel += new MouseEventHandler(this.OnMouseWheel);
    this.DoubleClick += new EventHandler(this.OnDoubleClick);
}

The postit control is painted with the help of the OnPaint and OnPaintBackground methods. Both methods are overridden: 

protected override void OnPaint(PaintEventArgs e)
{
    this.drawPostit(e.Graphics);                
}

private void drawPostit(Graphics controlGraphics)
{
    // define a rectangle to draw the image in. 
    // NOTE: Make the rectangle slightly larger than the original bitmap to avoid a black border.
    Rectangle imageRect = new Rectangle(0, 0, this.postitSize.Width+this.blackBorderWidth, 
        this.postitSize.Height+this.blackBorderHeight);
    controlGraphics.DrawImage(this.postitBitMap, imageRect);            
    
    // draw the text
    RectangleF textRect = new RectangleF(this.messageLeft, this.messageTop, this.postitSize.Width, 
        this.postitSize.Height);
    StringFormat drawFormat = new StringFormat();
    drawFormat.Alignment = StringAlignment.Center;            
    controlGraphics.DrawString(this.message, this.messageFont, this.messageColor, textRect,
        drawFormat);

    // draw the emergency flag if necessary
    if (this.isUrgent)
    {
        RectangleF urgentRect = new RectangleF(this.urgencyFlagLeft, this.urgencyFlagTop, 
            this.postitSize.Width / 10, 100);
        controlGraphics.DrawString("!", new Font("Tahoma", 50,FontStyle.Bold), Brushes.Red, 
            urgentRect);
    }
}

The drawPostit method first paints the bitmap. Thereafter, the message is painted with the given font. At last, the urgency flag is painted, if the flag is set. 

The OnPaintBackground-method is empty to avoid that the background is painted. This minimizes problems with flickering when the postit is moved. 

protected override void OnPaintBackground(PaintEventArgs pevent)
{
    //Don't allow the background to paint
}

Resizing of the postit is handled by the OnMouseWheel method:

protected void OnMouseWheel(object sender, MouseEventArgs e)
{
    this.resize(e);
}

private void resize(MouseEventArgs e)
{
    int width = this.Size.Width;
    int height = this.Size.Height;

    // make it larger
    if (e.Delta > 0)
    {
        if ((width + this.sizeDiff <= this.maxWidth)
        && (height + this.sizeDiff <= this.maxHeigth))
        {
            width += this.sizeDiff;
            height += this.sizeDiff;
        }
    }
    else // make it smaller
    {
        if ((width - this.sizeDiff >= this.minWidth)
        && (height - this.sizeDiff >= this.minHeigth))
        {
            width -= this.sizeDiff;
            height -= this.sizeDiff;
        }
    }

    // set the new size
    this.Size = new Size(width, height);
    this.postitSize = new Size(width - 25, height - 35);
}

As stated above, the size of the postit shall be reset through a double click:

protected void OnDoubleClick(object sender, EventArgs e)
{
    this.resetSize();
}

private void resetSize()
{
    this.Size = this.originalSize;
    this.postitSize = this.postitBitMap.Size;
}

Step 6: Implement the form

Now the postit control is ready and the following describe the creation of a Windows Form that uses the postit control:

The form contains the following controls:

  • a groupbox  (name=grpPostitSettings)
  • a label (name=lblMessageText)
  • a textbox (name=txtMessage)
  • ...and a button (name=btnCreatePostit)

Besides, the form has the following properties:

private Postit currentPostit = null;  // represents the currently selected postit
private List<Postit> postitList = new List<Postit>();

private Point ptStartPosition; // the start position of the postit when moving
private Point ptEndPosition; // the end position of the postit when moving

When the button is clicked, a new postit is created, event handlers are set and the control is added to the form: 

private void btnCreatePostit_Click(object sender, EventArgs e)
{
    Postit postit = new Postit(this.txtMessage.Text, new Font("Comic", 20), 
        Brushes.Green, PostitColor.FlatYellow, this.chkUrgent.Checked);
    postit.Location = new Point(5, 100);
    postit.MouseDown += new MouseEventHandler(this.OnMouseDown);
    postit.MouseMove += new MouseEventHandler(this.OnMouseMove);
    postit.BackColor = Color.FromKnownColor(KnownColor.Transparent);
    this.Controls.Add(postit);

    this.currentPostit = postit;
    this.postitList.Add(postit);
}

The mouse events MouseDown and MouseMove are handled here as well:

private void OnMouseDown(object sender, MouseEventArgs e)
{
    this.currentPostit = sender as Postit;
    this.ptStartPosition = this.PointToScreen(e.Location);
}

private void OnMouseMove(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        Cursor.Current = Cursors.SizeAll;
        this.ptEndPosition = this.currentPostit.PointToScreen(e.Location);
        ptEndPosition.Offset(-ptStartPosition.X, -ptStartPosition.Y);
        this.currentPostit.Location = ptEndPosition;
        this.Invalidate();
    }
}

History  

  • 2012-07-30: This is the first version.
  • 2012-08-09: Added the postit color as new property.

Helpful resources