Thursday, August 6, 2009

Getting data back from a thread

How do you get data back from a thread if you don't know when it'll finish running? You do it by using a delegate. When the code in the thread is complete, it'll call a delegate that is referenced back at the originating code.

Here are the basic steps:
  1. Define a delegate.
  2. public delegate void ReturnResult(object sender);
  3. In the class that contains the method to be called, create a field/property of your new delegate.
  4. public ReturnResult ReturnResultDelegate;
  5. In the class that starts the thread, define a method that matches your delegate's signature. This is the method that will be receiving the callback from the thread.
  6. static void CheckReturnedResult(object sender)
    {
        Math m = (Math) sender;
        Console.WriteLine("Result:" + m.Result);
    }
  7. Instantiate the class and set your delegate to the method you created.
  8. Math math = new Math();
    math.Value1 = 1;
    math.Value2 = 3;
    math.ReturnResultDelegate = CheckReturnedResult;
  9. Have your class call the delegate somewhere when the thread runs.
  10. public void Add(object o)
    {
        Result = Value1 + Value2;
        ReturnResultDelegate(this);
    }
Optionally, you can send just the return result back instead of the whole class.
Let's put everything together and see how it all works in this console application:
using System;
using System.Threading;

namespace ThreadingApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Math math = new Math();
            math.Value1 = 1;
            math.Value2 = 3;
            math.ReturnResultDelegate = CheckReturnedResult;

            ThreadPool.QueueUserWorkItem(math.Add);
            Thread.Sleep(1000);
        }

        static void CheckReturnedResult(object sender)
        {
            Math m = (Math)sender;
            Console.WriteLine("Result:" + m.Result);
        }
    }

    public class Math
    {
        public int Value1;
        public int Value2;
        public int Result;
        public delegate void ReturnResult(object sender);

        public ReturnResult ReturnResultDelegate;

        public void Add(object o)
        {
            Result = Value1 + Value2;
            ReturnResultDelegate(this);
        }
    }
}
In this sample, I minimize the scope of the delegate by including it in the class being called (Math). You might declare it outside the class if needed.

Another way to pass data into a thread

In the previous thread post I showed a way you can pass information into a thread. Here is another way in which you instantiate the class containing the method you want your thread to call first.
Math math = new Math();
math.Value1 = 1;
math.Value2 = 3;

ThreadPool.QueueUserWorkItem(math.Add);
Now when math.Add is called, it has all the information it needs to do its work.

Easiest way to start a thread

The easiest way to start a process on another thread is to call ThreadPool.QueueUserWorkItem.
Example:
// DoSomeWork is a method.
ThreadPool.QueueUserWorkItem(DoSomeWork);
Note: The DoSomeWork method has to have an Object as a parameter.
private static void DoSomeWork(object info)
{
    // Code that does work.
}
If you need to pass data into your method, you can do so:
ThreadPool.QueueUserWorkItem(DoSomeWork, "Info")
You will just have to cast the object back into the appropriate data type.
private static void DoSomeWork(object info)
{
    string workInfo = (string) info;
    // Code that does work.
}


More Info: MSDN: QueueUserWorkItem

Wednesday, August 5, 2009

Adding Text to Images

Adding text to an image requires 2 steps:
  • Create a Graphics object
  • Create a Font object
  • Call Graphics.DrawString method
Code Example:
private void Form1_Paint(object sender, PaintEventArgs e)
{
    Graphics g = e.Graphics;
    Font f = new Font("Arial", 12, FontStyle.Bold);
    g.DrawString("Copyright 2009", f, Brushes.Black, 10, 10);
}
Why would you do this?
Most likely you wouldn't. You would use a label instead. But you can also draw strings on images and that is most likely what you would use this method for.

More Info: MSDN: Graphics.DrawString Method

Tuesday, August 4, 2009

Assigning Images to Windows Controls

Use a Bitmap or Image class.
button1.BackgroundImage = new Bitmap("bm.jpg");
// or
pictureBox1.BackgroundImage = Image.FromFile("bm.jpg");


More Info: MSDN: Image Class

Creating and Saving a Picture

There are 3 steps to creating and saving a picture:
  1. Create a Bitmap object.
  2. Edit it using Graphics object.
  3. Call Bitmap.Save method to save it.

Code Example:
Bitmap bm = new Bitmap(100, 100);
Graphics g = Graphics.FromImage(bm);
g.DrawEllipse(new Pen(Color.Red), new Rectangle(5, 5, 90, 90));
bm.Save("bm.jpg", ImageFormat.Jpeg);
Here is what it looks like:
If you would like to edit an existing image instead, you can use:
Bitmap bm = new Bitmap("existingImage.jpg");

More Info: MSDN: Bitmap Class

Thursday, July 23, 2009

Nullable

When declaring a value type (int, bool, char, DateTime, etc.) you cannot initialize it to null or you'll get this error message: To fix this you need to declare your variable as nullable:
Nullable<bool> answer1 = null;
// or
bool? answer2 = null;
When this is done, 2 new properties become available to you, HasValue and Value. Now you can check if your variable has been assigned a value yet or if it's still null with HasValue.
if (answer1.HasValue) Console.WriteLine("answer1 is {0}", answer1);


More Info: MSDN: Nullable(T) Structure