Friday, June 19, 2009

C# Html Screen Scraping Part 1

This is the first post of a two part series.

Source Code: http://www.box.net/shared/i2p7t9kxkt

Very often, when a particular website has some information you'd like to use in your application, you'd see if they have some kind of API which you can use to query their data. However, it's very common for a website either to not have an API altogether, or not have that little bit of info you need made available in their API. What's done generally to get around this is a technique knows as "Screen Scarping". (Screen Scraping is a general term, not just for the web, but for the purpose of this blog, when I say Screen Scarping, I mean HTML Screen Scraping).

The general gist of it is this: when a browser contacts a site, an HTML document is sent back to the browser. The browser then has the (tedious) task of parsing out that HTML and rendering it out to the screen. End of the day though, the HTML is just a text file. What screen scraping basically is, you write an app that "acts" like a web browser, meaning it contacts the web site, downloads the HTML file into memory, at which point you're free to parse it out any which way you like and extract the data you need. In .NET this is incredibly easy to do, and I'll demonstrate a simple sample:


private string GetWebsiteHtml(string url)
{
WebRequest request = WebRequest.Create(url);
WebResponse response = request.GetResponse();
Stream stream = response.GetResponseStream();
StreamReader reader = new StreamReader(stream);
string result = reader.ReadToEnd();
stream.Dispose();
reader.Dispose();
return result;
}


Yup, that's pretty much it. First, you create a WebRequest object with the given URL. Then, you get a Response object out of that Request. Finally you get the response stream and read it with a StreamReader.

I attached a simple app so you can give it a whirl. Basically, it's a simple windows app with a textbox and a button. Enter any url in the textbox (make sure to write the full url including http://....) and hit the Go button. That will get you the entire HTML of that site, and display it in the richtextbox.

This is obviously a rough sample, make sure to add proper error handling, but other than that, it's pretty straightforward and real simple! The only thing to watch out for when scraping, is that your parsing code will rely on the HTML being formatted a VERY specific way. If the site changes in any way, your code WILL break.

This was a very simple post; in the next post, I'll take this much further, and demonstrate how we can actually POST to a server, and even get the cookies.

Monday, June 15, 2009

INotifyPropertyChanged - How to and when to?

Source Code: http://www.box.net/shared/nx8uj1rm1b

Databinding has always been fascinating to me; at first it really all looks like magic, how controls just track changes, and keep everything in sync. So much so, that very often I try to use it as little as possible, because I don't like using things I don't fully understand how they work. However, it does often save you from a lot of extra code, so I think it's very useful to explore it a bit, in particular the INotifyPropertyChanged interface.

Let's first start with a quick demo. Say you have a class, let's call is MyClass:



public class MyClass
{
public int MyProperty { get; set; }
}


Now let's say we have a Windows Form that has a DataGridView that we're using to bind to a BindingList of this type:



BindingList<MyClass> bindingList = new BindingList<MyClass>();
private void Bind()
{
bindingList.Add(new MyClass { MyProperty = 10 });
bindingList.Add(new MyClass { MyProperty = 20 });
bindingList.Add(new MyClass { MyProperty = 30 });
bindingList.Add(new MyClass { MyProperty = 40 });
this.dataGridView1.DataSource = bindingList;
}


This will work, and you'll have a DataGridView with one column called MyProperty with the rows 10,20,30,40. Very nice. Suppose however, that somewhere in the application, the contents of this list change (new values from database, or user input updated data, whatever..). You'll notice, that if your code applies changes directly to the BindingList, it will NOT reflect in the DataGridView:



public void UpdateList()
{
foreach (MyClass mc in this.bindingList)
{
mc.MyProperty = 100;
}
}


Just some simple code that changes all the MyProperty's to 100. You'll notice that these changes will NOT be reflected in the DataGridView. Well, the question becomes, how then do we have the changes reflected in the DataGridView? You COULD set the DataGridView's datasource to null and then rebind, but that's hacky and clumsy.

Enter the INotifyPropertyChanged interface. The interface has one property on it, and it's actually an event:



public interface INotifyPropertyChanged
{
// Summary:
// Occurs when a property value changes.
event PropertyChangedEventHandler PropertyChanged;
}


Looks quite simple, let's implement this now properly with a Person class. I've attached the source code to this post so you can download it and see for yourself. Here's the entire Person class:



public class Person : INotifyPropertyChanged
{

private string firstName;
private string lastName;
private int age;

public Person(string firstName, string lastName, int age)
{
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}

public Person()
{

}

protected virtual void OnPropretyChanged(string propertyName)
{
var handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}


public string FirstName
{
get
{
return this.firstName;
}
set
{
if (this.firstName != value)
{
this.firstName = value;
this.OnPropretyChanged("FirstName");
}
}
}

public string LastName
{
get
{
return this.lastName;
}
set
{
if (this.lastName != value)
{
this.lastName = value;
this.OnPropretyChanged("LastName");
}
}
}

public int Age
{
get
{
return this.age;
}
set
{
if (this.age != value)
{
this.age = value;
this.OnPropretyChanged("Age");
}
}
}

#region INotifyPropertyChanged

public event PropertyChangedEventHandler PropertyChanged;

#endregion
}


The first thing you'll notice is that I implemented INotifyPropertyChanged. Then, in each setter of the properties, I call a method called "OnPRopertyChanged" which actually raises the event. The only downside of this, is that you can't use auto properties because the setters need to have logic. Also, since we'll be raising an event every time the value changes, it's worth putting in the extra if check:


if (this.firstName != value)
{
this.firstName = value;
this.OnPropretyChanged("FirstName");
}


just to make sure that the value actually changed.

I then created a simple Form that has a DataGridView that's bound to a BindingList<Person>. It also has a button, that when clicked, adds 5 years to everyones age.



public partial class Form1 : Form
{

private BindingList<Person> people;

public Form1()
{
InitializeComponent();
this.people = new BindingList<Person>();
this.PopulatePeople();
this.dataGridView1.DataSource = people;
}

private void PopulatePeople()
{
this.people.Add(new Person("Alex", "Friedman", 27));
this.people.Add(new Person("Jack", "Bauer", 45));
this.people.Add(new Person("Tony", "Almeda", 39));
this.people.Add(new Person("Chloe", "O'Brien", 37));
this.people.Add(new Person("Bill", "Buchanan", 50));
}

private void ChangeAges()
{
foreach (Person p in this.people)
{
p.Age += 5;
}
}

private void buttonChange_Click(object sender, EventArgs e)
{
this.ChangeAges();
}
}


If you run this, you'll notice that DataGridView does in fact get updated, even though I just manipulated the underlying list. I never actually touch the DataGridView itself. Internally, the BindingList checks to see if the class of type T (remember, BindingList is generic) implements INotfiyPropertyChanged. If it does, it hooks into that event, and when the event is raised, it updates itself.

The one thing to be careful is that when raising this event, you actually hardcode the name of the property. Personally, I wish there was a better way, but anything I've seen online so far had some serious overhead (like using the StackFrame to figure out which property is changing) so if someone knows of a better way, please let me know!

UPDATE: I recently blogged about a better approach to dealing with the INotifyPropertyChanged event that takes care of the hardcoded strings issue. Check it out here.

Thursday, June 11, 2009

Tweaking a DataGridView ComboBoxColumn to allow editing.

Let me first say this. I love the DataGridView and I think it's an awesome and very versatile control. It's highly customizable, and you can create a damn near excel-like application around it. Having said that though, anyone who's ever used a DataGridView knows just how "quirky" the stupid thing can be. Things that look like they should be simple, require clever hacks to implement.

Recently, I was creating an in-house app here at work, in which I needed a DataGridView with a ComboBoxColumn but with one wrinkle. Out of the box, the ComboBoxColumn doesn't support editing. Meaning, it acts like a ComboBox that has the DropDownStyle set to DropDownList (which doesn't allow the user to enter new values). We, however, did need to have the ability for the user to enter new values. I thought that this would be a simple property that I'd be able to set on the ComboBoxColumn. Yea, well there is no such property, so queue clever hack!

The first thing you need to do is hook into the DataGridView's EditingControlShowing event. This event fires when the actual ComboBox is "dropped down". The interesting thing is that the EventArgs has a property on it "Control" that can be cast to a standard WinForms ComboBox.

To demonstrate, I've created a simple Windows App that has a button on it and a DataGridView. It also has a method that just returns a list of strings that contains all the days of the week (needed something just for testing). When the button is clicked, the DataGridView gets populated with a ComboBoxColumn with all the days. Here's the entire code:



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;

namespace DataGridViewComboBoxTesting
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.dataGridView1.EditingControlShowing += HandleEditShowing;
}

private void HandleEditShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
var cbo = e.Control as ComboBox;
if (cbo == null)
{
return;
}

cbo.DropDownStyle = ComboBoxStyle.DropDown;
cbo.Validating -= HandleComboBoxValidating;
cbo.Validating += HandleComboBoxValidating;
}

private void HandleComboBoxValidating(object sender, CancelEventArgs e)
{
var combo = sender as DataGridViewComboBoxEditingControl;
if (combo == null)
{
return;
}
if (!combo.Items.Contains(combo.Text)) //check if item is already in drop down, if not, add it to all
{
var comboColumn = this.dataGridView1.Columns[this.dataGridView1.CurrentCell.ColumnIndex]
as DataGridViewComboBoxColumn;
combo.Items.Add(combo.Text);
comboColumn.Items.Add(combo.Text);
this.dataGridView1.CurrentCell.Value = combo.Text;
}
}

private void button1_Click(object sender, EventArgs e)
{
var cboColumn = new DataGridViewComboBoxColumn
{
Name = "ComboBox",
HeaderText = "Combo Box Column"
};

foreach (var day in this.GetListOfStrings())
{
cboColumn.Items.Add(day);
}

this.dataGridView1.Columns.Add(cboColumn);
}

public IEnumerable<string> GetListOfStrings()
{
foreach (var day in Enum.GetValues(typeof(DayOfWeek)))
{
yield return day.ToString();
}
}
}
}


As you can see, in the HandleEditShowing method, we can get access the the underlying ComboBox itself, and set the DropDownStyle property right there. We then do a little more hackery so that when the user enters a new value, we can add it to all other ComboBox's in that column. We do that by hooking into the ComboBox's Validating event (first we unhook it in case we're already hooked into it, so that our event handler doesn't get called more than once).


private void HandleEditShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
var cbo = e.Control as ComboBox;
if (cbo == null)
{
return;
}

cbo.DropDownStyle = ComboBoxStyle.DropDown;
cbo.Validating -= HandleComboBoxValidating;
cbo.Validating += HandleComboBoxValidating;
}


The event handler then looks like this:



private void HandleComboBoxValidating(object sender, CancelEventArgs e)
{
var combo = sender as DataGridViewComboBoxEditingControl;
if (combo == null)
{
return;
}
if (!combo.Items.Contains(combo.Text)) //check if item is already in drop down, if not, add it to all
{
var comboColumn = this.dataGridView1.Columns[this.dataGridView1.CurrentCell.ColumnIndex] as DataGridViewComboBoxColumn;
combo.Items.Add(combo.Text);
comboColumn.Items.Add(combo.Text);
this.dataGridView1.CurrentCell.Value = combo.Text;
}
}


Simple. We just check if it's already in the list, if it's not then add it to the combo box as well as add it to all other combo boxes.

Here's a link to the source code. In the code I also created a class called DataGridViewComboBoxColumnEx which basically inherits from DataGridViewComboBoxColumn and encapsulates all this hackery nicely. You just use it as you normally would but it allows editing.

Source code: http://www.box.net/shared/73bmzmv1r6

Tuesday, June 9, 2009

How do closures / captured variables work under the hood?

First, a little disclaimer. I'll be using 3.0 syntax with Lambda's but this has been around since .NET 2.0 and anonymous methods.

Ok, so first a little demonstration:



namespace ClosureDemo
{
public delegate void StuffDoer();

class Program
{
static void Main(string[] args)
{
var stuffDoerDelegate = GetDelegate();
stuffDoerDelegate();
stuffDoerDelegate();

Console.ReadKey(true);

}

private static StuffDoer GetDelegate()
{
int counter = 1;
StuffDoer result = () =>
{
counter++;
Console.WriteLine(counter);
};
result();
return result;
}

}
}


Simple little app. First, I create a delegate type called "StuffDoer" that has a return type of void, and takes no parameters. Then, I have a private method that news up a StuffDoer delegate, and attaches an anonymous method to it. Here's the interesting thing to note though: I declared a variable called counter outside of the anonymous method. The obvious question that comes to mind is how? Shouldn't counter be outside of scope? If you didn't declare this as an anonymous method, but rather as a concrete method:



private static StuffDoer GetDelegate()
{
int counter = 1;
StuffDoer result = new StuffDoer(DoStuff);
return result;
}

private static void DoStuff()
{
counter++;
Console.WriteLine(counter);
}


This obviously wouldn't compile because counter is undefined in the DoStuff method. So how can it work in the anonymous method? Furthermore, you'll notice, that if you run this program, it prints out 2, 3 and 4 which shows us that the counter variable somehow stuck around?? How? We declared it once inside our GetDelegate method, shouldn't it have been lost after we left that method? How did it retain it's state?

This is knows as "closures" or "captured variables" and was always just one of those "black magic it just works" kinda thing for me. I researched it, thought I kinda understood it, but never QUITE got it. Recently, however, I picked up a copy of Jon Skeet's C# In Depth book (I CANNOT stress enough how great this book is! I'm only halfway through, didn't even start with the C# 3.0 / .NET 3.5 stuff yet, and already I've learned tons of stuff. I HIGHLY recommend it!) and it opened my eyes as to what exactly is going on under the covers. I'll admit, it may not really matter at the end of the day, you could just stick with the "it just works" attitude, but I like trying to understand how stuff works under the covers.

The first thing to understand is that the compiler is smart. Very smart. It notices that the counter variable is being "captured" and does some funky stuff for us. If you open reflector, you can see what exactly happened here:



You'll notice that there's a class there that I never created. You'll see it there as "<>c__DisplayClass1". And if you look at the code, it looks something like this:



[CompilerGenerated]
private sealed class <>c__DisplayClass1
{
// Fields
public int counter;

// Methods
public void <GetDelegate>b__0()
{
this.counter++;
Console.WriteLine(this.counter);
}
}



Ok, we're getting somewhere; a class was created for us with the counter variable as a public member, as well as a public method that looks just like our anonymous method. Very cool.....but how exactly does that help us? Now, if we look back in our "GetDelegate" method in Reflector, this is what we see:



private static StuffDoer GetDelegate()
{
<>c__DisplayClass1 CS$<>8__locals2 = new <>c__DisplayClass1();
CS$<>8__locals2.counter = 1;
StuffDoer result = new StuffDoer(CS$<>8__locals2.<GetDelegate>b__0);
result();
return result;
}


Looks like a mess with all the compiler generated stuff, but we can finally see the big picture. I'll rewrite the code in "plain english" so you can see what's going on:

First, I create a counter class: (this is instead of the "<>c__DisplayClass1" the compiler generated.)



public class CounterClass
{
public int counter;

public void DoSomething()
{
counter++;
Console.WriteLine(counter);
}
}


Then, back in the Program.cs, let's change the GetDelegate method to this:



private static StuffDoer GetDelegate()
{
CounterClass c1 = new CounterClass();
c1.counter = 1;
StuffDoer result = new StuffDoer(c1.DoSomething);
result();
return result;
}


Here's the key. As I've pointed out in the past, delegates are objects, and can hold references to other objects. So, what's happening here is, an instance of our CounterClass is created, and we pass in one of it's methods to a new instance of the StuffDoer delegate. This now causes the delegate to hold a reference to this CounterClass object. Then, every time after that, when you invoke the delegate, it's still holding a reference to the same object it had in the beginning so you're constantly calling the methods on the same object!

Now it all makes sense; that's how it can reference the counter variable inside the anonymous method, because it's actually a method in a class that's referencing it's own public member. And now also we understand how it maintains state, because it's just a regular object that's being kept around. Smart smart compiler :)

Wednesday, June 3, 2009

Lesson learned....RTFM!

A few weeks ago, I was tasked with writing a site map generator for our new site at work that uses ASP.NET MVC. When using ASP.NET MVC Controllers have "Actions" that map to URL's. For the sake of this blog point, all that's important to know is that generally Actions are methods that return an ActionResult object. So, the idea was, in order to generate the site map correctly, I would use reflection to inspect the entire assembly, and any method that returned an ActionResult would be entered into the site map with the correct XML.

The catch however was that in many instances, the return type of our Action's weren't actually ActionResult objects, but rather classes the derived from ActionResult. (Some that are built into ASP.NET MVC and some custom ones.) So, I quickly realized I needed a method that you can pass in a type, along with another type, and the method would tell you if anywhere up the inheritance chain, type1 inherits from type2.

My first thought was "Perfect! I'll just use recursion!" This quickly got me excited, because it's not every day you get to use recursion in a useful piece of production code, much less when it came to reflection. So, I ended up writing an extension method that crawls up the inheritance chain recursively and it worked perfectly. Here's the code:

public static class TypeExtensions
{
public static bool InheritsFrom(this Type type, Type baseType)
{
if (baseType == null || type == null)
{
return false;
}

if (type.BaseType == baseType)
{
return true;
}

return type.BaseType.InheritsFrom(baseType);
}
}


Basically, the Type class has a handy property called BaseType which basically gives you the BaseType (duh!). If the Type is object, then BaseType is null, in which case we know we've reached the top of the inheritance chain, and we're done. To test this method out, let's whip up some demo code:



public class MyMemoryStreamBase : MemoryStream
{

}

public class MyMemoryStreamChild : MyMemoryStreamBase
{

}

public class MyMemoryStreamGrandChild : MyMemoryStreamChild
{

}
Basically, I've created a nice Inheritance chain that goes up to MemoryStream -> Stream -> MarshalByRefObject and finally object. Here's how you can test it:


Type type = typeof(MyMemoryStreamGrandChild);
bool result = type.InheritsFrom(typeof(MarshalByRefObject));
Console.WriteLine(result);

If you run this, the result will be True, proving that my cute little method worked, and I was all happy.

Fast forward a few weeks, and while browsing StackOverflow, I came across a question regarding reflection and BaseType's when some dude posts a link to this:

Type.IsSubClassOf(..)

Yeah, that's right! It's built right into the .NET Framework! Now obviously it's impossible to know of every method in the framework, but as soon as I thought of the need, and that it involved recursion, I simply whipped out Visual Studio and started coding, without actually taking a moment and thinking, hey research this first! You can't be the FIRST person to come across this very issue!

Feeling completely beat, I was just curious at this point as to how it's implemented in the Framework. Were they also using recursion, or did they have some other ingenious way of doing this. Well here's how they did it:



public virtual bool IsSubclassOf(Type c)
{
Type baseType = this;
if (baseType != c)
{
while (baseType != null)
{
if (baseType == c)
{
return true;
}
baseType = baseType.BaseType;
}
return false;
}
return false;
}

Yea, no recursion, just a simple while loop. At this point, I was just curious in general as to which method is quicker. So, some quick benchmarks:




public void CompareMethodsSpeed()
{
Stopwatch watch = new Stopwatch();
Type type = typeof(MyMemoryStreamGrandChild);
Type baseType = typeof(MarshalByRefObject);
watch.Start();
for (int i = 0; i < 100000; i++)
{
type.InheritsFrom(baseType);
}
watch.Stop();
Console.WriteLine("My way took: {0} ticks.", watch.ElapsedTicks);

watch.Reset();

watch.Start();
for (int i = 0; i < 100000; i++)
{
type.IsSubclassOf(baseType);
}
watch.Stop();
Console.WriteLine("Their way took: {0} ticks.", watch.ElapsedTicks);
}


Then I ran this one my machine and the results were:

My way took: 107433 ticks.
Their way took: 41684 ticks.

So yea, I got my butt whooped!! I'll chalk this one up to experience.

Moral of the story? Two things. First, not just because you CAN do it with recursion, does that mean you SHOULD do it that way. Second, RTFM!! Chances are, MS has more time to test various ways of doing certain things, so double check that something is in the Framework before rolling your own.

The only one thing I'll say in my (somewhat weak) defense is that InheritsFrom is a MUCH better name for this method than IsSubslassOf IMO. So yea, name your methods better MS!!

Tuesday, June 2, 2009

Creating a Splash Screen in .NET with a progress bar.

EDIT: I've added a link to the source code: http://www.box.net/shared/xbo9xvlguu

Many times an application needs to do many time consuming operations at start-up. Sometimes you need to read data from a database, sometimes you may need to retrieve some data from a web service. When this happens, it's often useful to display a "Splash Screen" to the user, with a company logo or something, along with a progress bar to indicate how much longer it will take for the app to load. While it may sound simple at first, it can be a bit tricky; if you simply show a screen, and do your time consuming operations, your UI will hang and your progress bar will never update. Therefore, there's some threading involved (not too much, don't get scared!), so I'll demonstrate a simple example here.

Start off by creating a simple Windows Forms project. Once it's loaded, add another windows form (besides for the Form1 that's already there) and call it "SplashScreen". To get the look and feel right, let's set some properties:

  • FormBorderStyle: None
  • TopMost : True
  • StartPosition: CenterScreen
Now, in the properties window, find the BackgroundImage property and click the little elipsis {...} and select a picture from your hard drive. I also then changed the BackgroundImageLayout property to None but you can do whatever you want. Then, add a progress bar to the bottom of the form, and set the Dock property to Bottom. Here's what my splash screen looks like in the designer: (not sure why I chose a Halo picture....)

Now, we need to give access to someone outside of this class to update the progress (the progressBar is a private member and can't be accessed.) Here's the problem; if we simply wrap the progress bar's Value property in our own getter/setter like this:



public int Progress
{
get
{
return this.progressBar1.Value;
}
set
{
this.progressBar1.Value = value;
}
}

while you can do that, remember, this splash screen will be shown in a seperate thread. If you then try to access this property from your main thread, you'll get an InvalidOperationException that "Cross-thread operation not valid: Control 'progressBar1' accessed from a thread other than the thread it was created on." So, in order to be able to set any of the UI elements from another thread, we need to call the form's Invoke method which takes a delegate. Here's the complete code for the SplashScreen class:


using System.Windows.Forms;

namespace SplashScreenTesting
{
public partial class SplashScreen : Form
{
private delegate void ProgressDelegate(int progress);

private ProgressDelegate del;
public SplashScreen()
{
InitializeComponent();
this.progressBar1.Maximum = 100;
del = this.UpdateProgressInternal;
}

private void UpdateProgressInternal(int progress)
{
if (this.Handle == null)
{
return;
}

this.progressBar1.Value = progress;
}

public void UpdateProgress(int progress)
{
this.Invoke(del, progress);
}
}
}

As you can see, we created a delegate that we'll use to invoke the update to the progress bar. (The reason why I have a null check for this.Handle is because I was getting an exception right at the start up that the Handle wasn't created yet.)

Ok, now let's create a class that simulates a time consuming operation. Basically, it just calculates Math.Pow for numbers 1 - 100 raised to the 1 - 500,000th power. Every time we move on to another outer number (the 1 - 100) we raise an event that reports progress. Once it's done, we raise an event that we're done. Here's the complete class:



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SplashScreenTesting
{
public class Hardworker
{
public event EventHandler<HardWorkerEventArgs> ProgressChanged;
public event EventHandler HardWorkDone;

public void DoHardWork()
{
for (int i = 1; i <= 100; i++)
{
for (int j = 1; j <= 500000; j++)
{
Math.Pow(i, j);
}
this.OnProgressChanged(i);
}

this.OnHardWorkDone();
}

private void OnProgressChanged(int progress)
{
var handler = this.ProgressChanged;
if (handler != null)
{
handler(this, new HardWorkerEventArgs(progress));
}
}

private void OnHardWorkDone()
{
var handler = this.HardWorkDone;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}

public class HardWorkerEventArgs : EventArgs
{
public HardWorkerEventArgs(int progress)
{
this.Progress = progress;
}

public int Progress
{
get;
private set;
}
}
}


I also created a custom event args so that we can pass the progress on to the subscriber of our ProgressChanged event. (As a side note, if you're wondering about the strange assignement taking place when raising the event, see Eric Lippert's blog on the subject.)

Now, on to the main part of the app; the displaying of the splash screen. In the Form1's load event, we'll spawn off another thread to actually display the splash screen and then on the main thread we'll do our "Hard Work". Once the HardWorker has reported that the progress is complete, we'll dispose of the splashscreen and display the main Form. Here's the code, I'll try my best to explain:

using System;
using System.Windows.Forms;
using System.Threading;

namespace SplashScreenTesting
{
public partial class Form1 : Form
{
private SplashScreen splashScreen;
private bool done = false;
public Form1()
{
InitializeComponent();
this.Load += new EventHandler(HandleFormLoad);
this.splashScreen = new SplashScreen();
}

private void HandleFormLoad(object sender, EventArgs e)
{
this.Hide();

Thread thread = new Thread(new ThreadStart(this.ShowSplashScreen));
thread.Start();

Hardworker worker = new Hardworker();
worker.ProgressChanged += (o, ex) =>
{
this.splashScreen.UpdateProgress(ex.Progress);
};

worker.HardWorkDone += (o, ex) =>
{
done = true;
this.Show();
};

worker.DoHardWork();
}



private void ShowSplashScreen()
{
splashScreen.Show();
while (!done)
{
Application.DoEvents();
}
splashScreen.Close();
this.splashScreen.Dispose();
}
}
}

In the constructor we just hook into the Load event and new up the SplashScreen. Then, in the Load event handler, we first hide the current form, because we don't want that to be seen just yet. We then create a Thread and pass in a delegate to our ShowSplashScreen method. The show splash screen method is what's actually going to be run on a seperate thread. First, it displays the SplashScreen. Then, it just sits there in a constant loop waiting for the "done" bool to be set to true. The key ingredient here is the call to Application.Doevents(). I think Microsoft does a good job explaining what this does so I'll let them do that talking:

When you run a Windows Form, it creates the new form, which then waits for events to handle. Each time the form handles an event, it processes all the code associated with that event. All other events wait in the queue. While your code handles the event, your application does not respond. For example, the window does not repaint if another window is dragged on top.

If you call DoEvents in your code, your application can handle the other events. For example, if you have a form that adds data to a ListBox and add DoEvents to your code, your form repaints when another window is dragged over it. If you remove DoEvents from your code, your form will not repaint until the click event handler of the button is finished executing. For more information on messaging, see User Input in Windows Forms.


Basically, it allows other events to be taken care of, even though the current procedure is blocking execution. This allows our progress bar to be updated.

Back in the form load, we then new up our HardWorker and hook into it's events. (I'm using the more terse Lambda syntax, see my previous blog post on the subject here for more information.) Basically, every time the HardWorker reports progress, we update our progress bar. Then when it's done, we set our done flag to true, and show the main form. Finally, we actually kick it off with a call to DoHardWork();

Try it out and run it. It's actually kinda neat to see it in action. This is obviously a very rough example, but it should give you a basic idea on how to get this done.

Sunday, May 24, 2009

When KeyPressed / KeyDown just isn't enough. An adventure in GetKeyboardState.

Source Code: http://www.box.net/shared/y7v5jskfd1

A question on StackOverflow this weekend, piqued my interest. It was about some guy that was creating a Tetris game in C# (using Winforms) and was having issues with keyboard input. Basically, he was hooking into the Forms KeyDown event, and if the key was either left down or right, he'd move the tetris piece accordingly. The problem he was running into was if the user would hold down more than one key at a time (which is very common when playing Tetris or any other game for that matter), only one key would register.

Having messed with XNA in the past (I still hope to release a game to the XBOX Community games in this life time :-P ), I had a hunch. In XNA, things work a little different. A little background on how games work in general. All games consist of a "Game Loop". Basically, the entire application runs in one gigantic loop. You have a timer that constantly runs in the background, and every time the timer "ticks" two things happen. Update() is called, and Draw() is called. During the update routine, you update your game logic, ie: move player's position, move enemies position etc.. Then, during the Draw routine, you draw everything to screen.

It is during this Update routine, where you "poll" the keyboard (or gamepad when working on the XBOX 360) to find out what's going on. Here's a small sample:

56 var state = Keyboard.GetState();

57 bool downPressed = state.IsKeyDown(Keys.Down);


As you can see, you "ask" the keyboard if the Down key is pressed at the current time. The cool thing about this method is that you can "ask" for multiple keys in one trip. There's nothing stopping you from doing this:

56 var state = Keyboard.GetState();

57 bool downPressed = state.IsKeyDown(Keys.Down);

58 bool upPressed = state.IsKeyDown(Keys.Up);



In Windows Forms though, if you listen for the KeyDown event, the KeyEventArgs will give you the Keycode, but only of ONE key. So, if more than one key is pressed, what do you do?

After some searching, I found that there's a "GetKeyboardState" function that's part of the Win32 API. We should be able to P/Invoke this function, and poll the keyboard for more than one key. According to the Microsoft documentation, you pass in the int value of the key, and you get back a short.

The return value specifies the status of the specified virtual key, as follows:

  • If the high-order bit is 1, the key is down; otherwise, it is up.
  • If the low-order bit is 1, the key is toggled. A key, such as the CAPS LOCK key, is toggled if it is turned on. The key is off and untoggled if the low-order bit is 0. A toggle key's indicator light (if any) on the keyboard will be on when the key is toggled, and off when the key is untoggled.
So, I found this helpful little class online that wraps this API call nicely.

First, a simple struct to hold the Key's state:



public struct KeyStateInfo
{
private Keys key;
private bool isPressed;
private bool isToggled;

public KeyStateInfo(Keys key, bool ispressed, bool istoggled)
{
this.key = key;
isPressed = ispressed;
isToggled = istoggled;
}

public static KeyStateInfo Default
{
get
{
return new KeyStateInfo(Keys.None, false, false);
}
}

public Keys Key
{
get { return key; }
}

public bool IsPressed
{
get { return isPressed; }
}

public bool IsToggled
{
get { return isToggled; }
}
}

Then, here's the actual class that wraps the P/Invoke:



using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

public class KeyboardInfo
{
private KeyboardInfo() { }
[DllImport("user32")]
private static extern short GetKeyState(int vKey);

public static KeyStateInfo GetKeyState(Keys key)
{
short keyState = GetKeyState((int)key);
int low = Low(keyState), high = High(keyState);
bool toggled = low == 1;
bool pressed = high == 1;
return new KeyStateInfo(key, pressed, toggled);
}
private static int High(int keyState)
{
return keyState > 0 ? keyState >> 0x10
: (keyState >> 0x10) & 0x1;
}
private static int Low(int keyState)
{
return keyState & 0xffff;
}
}


Simple enough. To prove that this works now with more than one key, I wrote a simple windows app that moves a ball around the form based on the user's pressing of the arrow keys. You'll notice, that if you press two arrows at once, it will move the ball diagonally, proving that it accepts more than one key at a time. Here's the code:

First, I created a simple Ball class:



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace WindowsFormsApplication1
{
public class Ball
{
private Brush brush;

public float X { get; set; }
public float Y { get; set; }
public float DX { get; set; }
public float DY { get; set; }
public Color Color { get; set; }
public float Size { get; set; }

public void Draw(Graphics g)
{
if (this.brush == null)
{
this.brush = new SolidBrush(this.Color);
}
g.FillEllipse(this.brush, X, Y, Size, Size);
}

public void MoveRight()
{
this.X += DX;
}

public void MoveLeft()
{
this.X -= this.DX;
}

public void MoveUp()
{
this.Y -= this.DY;
}

public void MoveDown()
{
this.Y += this.DY;
}
}

}


This class basically holds the coordinates of the ball, and the "velocity" (DX, and DY), or the speed at which the ball will move each time the key is pressed. It also holds the color and size.

Then, here's the main Form code:



using System;
using System.Drawing;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private Ball ball;
private Timer timer;
public Form1()
{
InitializeComponent();
this.ball = new Ball
{
X = 10f,
Y = 10f,
DX = 2f,
DY = 2f,
Color = Color.Red,
Size = 10f
};
this.timer = new Timer();
timer.Interval = 20;
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
}

void timer_Tick(object sender, EventArgs e)
{
var left = KeyboardInfo.GetKeyState(Keys.Left);
var right = KeyboardInfo.GetKeyState(Keys.Right);
var up = KeyboardInfo.GetKeyState(Keys.Up);
var down = KeyboardInfo.GetKeyState(Keys.Down);

if (left.IsPressed)
{
ball.MoveLeft();
this.Invalidate();
}

if (right.IsPressed)
{
ball.MoveRight();
this.Invalidate();
}

if (up.IsPressed)
{
ball.MoveUp();
this.Invalidate();
}

if (down.IsPressed)
{
ball.MoveDown();
this.Invalidate();
}


}


protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (this.ball != null)
{
this.ball.Draw(e.Graphics);
}
}
}


}

First, I create a red ball that's 10 pixels in size. Then, I create a Timer which will "tick" every 20 milliseconds. This is simple to simulate a game loop. It won't actually "Draw" every tick, it will only ever redraw if one of the arrow keys is pressed. The event handler for the Timer is where the meat of this lies:


void timer_Tick(object sender, EventArgs e)
{
var left = KeyboardInfo.GetKeyState(Keys.Left);
var right = KeyboardInfo.GetKeyState(Keys.Right);
var up = KeyboardInfo.GetKeyState(Keys.Up);
var down = KeyboardInfo.GetKeyState(Keys.Down);

if (left.IsPressed)
{
ball.MoveLeft();
this.Invalidate();
}

if (right.IsPressed)
{
ball.MoveRight();
this.Invalidate();
}

if (up.IsPressed)
{
ball.MoveUp();
this.Invalidate();
}

if (down.IsPressed)
{
ball.MoveDown();
this.Invalidate();
}
}

First, we "poll" the keyboard for the arrows keys. We poll for all four of them, therefore if more than one is pressed, we'll be able to react to all of them. Then, if either key is held down, we move the ball in that direction and call Invalidate() to allow the form to repaint itself.

One final thing I'd like to point out, is that with the standard KeyDown event in Windows Forms, you can get "modifiers" (Shift, Ctrl, Alt etc.) as well as the key that was pressed. So if you're writing an app where you want to have some shortcut like say CTRL + A, you don't need to do this. This is only when you want to get info on more than one standard key................Which is why, you'll probably never need this in a real app outside of games (in which case, you're better off with XNA) but it's still something that's good to know.