Tuesday, November 24, 2009

Compact Framework and NUnit

I have the idea of a small application I could write for the Windows Mobile. The application will only use its local SQL Server database, at least initially, and it is really simple to create a local database on the device. The only things I need are the physical location of the sdf file on the device and the connection string.

In my "DataBase" class I generate them

private string GetLocalDatabasePath()
{
string applicationPath = Path.GetDirectoryName(this.GetType().Assembly.GetName().CodeBase);
string localDatabasePath = applicationPath + Path.DirectorySeparatorChar +
"TTrack.sdf";
return localDatabasePath;
}

private string GetLocalConnectionString()
{
string localConnectionString = "Data Source=" +
GetLocalDatabasePath();

return localConnectionString;
}

To create a database I just check if the database file already exists, and if not - I create it. Also, for testing purposes, the delete database function is used.

internal void CreateDatabase()
{
if (!File.Exists(localDatabasePath))
{
using (SqlCeEngine engine = new SqlCeEngine(localConnectionString))
{
engine.CreateDatabase();
}

RunNonQuery(qryCreateTables);
}
}

internal void DeleteDatabase()
{
string dbPath = GetLocalDatabasePath();
if (File.Exists(dbPath))
{
File.Delete(dbPath);
}
}

The RunNonQuery bit is just the creation of tables in the database.

internal void RunNonQuery(string query)
{
string connString = GetLocalConnectionString();

using (SqlCeConnection cn = new SqlCeConnection(connString))
{
cn.Open();
SqlCeCommand cmd = cn.CreateCommand();
cmd.CommandText = query;
cmd.ExecuteNonQuery();
}
}

The query for now just creates the simplest possible "dummy" table

internal string qryCreateTables = "CREATE TABLE Users (" +
"UserID uniqueidentifier PRIMARY KEY DEFAULT NEWID() NOT NULL, " +
"Name NVARCHAR(50) NOT NULL )";

The RunScalar, obviously, is used to run ExecuteScalar(). Some refactoring still required to improve the code.

internal int RunScalar(string query)
{
string connString = GetLocalConnectionString();

using (SqlCeConnection cn = new SqlCeConnection(connString))
{
cn.Open();
SqlCeCommand cmd = cn.CreateCommand();
cmd.CommandText = query;
return int.Parse(cmd.ExecuteScalar().ToString());
}
}

Now that I can create a database, I can run this simple bit of code to see if it is working.

DataBase db = new DataBase();
db.CreateDatabase();
db.RunNonQuery(db.qryInsertRecord);
MessageBox.Show(db.RunScalar(db.qryCountUsers).ToString());

Database gets created, a record gets inserted, a messagebox with "1" is shown. All is well.

Next, I decide to quickly create and run a simple test for database creation: If the database is present, I delete it, then create a new one, insert one record and test for the count of records indeed being one.

Here is the test I write in NUnit.

[Test]
public void CheckDatabaseCreation()
{
DataBase db = new DataBase();
db.SetFileName(@"\Program Files\TestDB\TTrack.sdf");
db.SetConnectionString(@"Data Source=\Program Files\TestDB\TTrack.sdf");
db.DeleteDatabase();
db.CreateDatabase();
db.RunNonQuery(db.qryInsertRecord);
int count = db.RunScalar(db.qryCountUsers);
Assert.AreEqual(count, 1);
}

This does not go as well, however:

What happened there? Oh, of course - the NUnit test runs on the desktop, but the code is supposed to run on the emulator (I don't use the actual device yet). So, it looks like I will have to work on the approach to testing ...

by . Also posted on my website

Thursday, November 19, 2009

Compact Framework and forms management.

This was my first experience with the Microsoft Compact Framework. The application is developed in Visual Studio 2005 and is targeted to run on Pocket PC 2003 devices. Basically, I had to extend a simple application that had only one form to add some functionality and a few more forms. I understand that the forms in Compact Framework are treated a bit differently compared to a desktop application. What to use for navigation between forms, Show() or ShowDialog()? I decided to use Show() because I have only about 5 forms, most of those are very simple and also, my application will be the only one running on the device. So I thought, if I create each form once and keep them all in memory, just showing and hiding them, it may use more memory, which I do not care that much about, but be easier on the device battery. Okay, I may be saying total nonsense here - I have about 7 days Compact Framework development experience at this very moment.

So I have a dictionary where all existing forms are kept.

private static Dictionary _applicationForms = new Dictionary();

And the function that gets the form from the dictionary by name.

internal static Form GetFormByName(string formName)
{
if (_applicationForms.ContainsKey(formName))
{
return _applicationForms[formName];
}
else
{
Form newForm = CreateFormByName(formName);
AddFormIfNotExists(newForm);
return newForm;
}
}

And the function to create a form if it has not been yet created.

private static Form CreateFormByName(string name)
{
Form form = new Form();

switch (name)
{
case Constants.frmFirst:
form = new frmFirst();
break;

...

case Constants.frmLast:
form = new frmLast();
break;
default:
form = new frmLast();
break;
}
return form;
}

And the function to add the form to the dictionary if it is not there.

internal static void AddFormIfNotExists(Form frm)
{
if (!_applicationForms.ContainsKey(frm.Name))
{
_applicationForms.Add(frm.Name, frm);
}
}

And when I need to show another form, I get it from the dictionary and show, and hide the current form.

internal static void ShowFromForm(Form source, string targetName)
{
Form frm = GetFormByName(targetName);
frm.Show();
source.Hide();
}

There's a bit more to it, sometimes I need to find which form is currently visible etc, but these are the core things. Stupid? Good enough? I don't know ...

by . Also posted on my website