Sunday, August 30, 2009

How to listen for KeyPress events in a DataGridView

When listening to KeyPress events in a DataGridView, you will only listen to events when the actual DataGridView control has focus, and not when you are typing text in a column (e.g. DataGridViewTextBoxColumn) in the grid.
If you want to listen to key events (or any event) in the column, you need to first listen to an event that will fire when the DataGridViewTextBoxColumn control is entering editing mode.

FooDataGridView += DataGridViewEditingControlShowingEventHandler(FooDataGridView_EditingControlShowing);

Then you will be able to listen for the KeyPress event:

private TextBox areaValueTextBox = null;

void FooDataGridView_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
    if (e.Control is TextBox)
    {
        if (areaValueTextBox == null)
        {
            areaValueTextBox = e.Control as TextBox;
            areaValueTextBox.KeyPress += new KeyPressEventHandler(areaValueTextBox_KeyPress);
        }
        else
            areaValueTextBox = e.Control as TextBox;
    }
}

void areaValueTextBox_KeyPress(object sender, KeyPressEventArgs e)
{
    System.Diagnostics.Debug.WriteLine("==> " + areaValueTextBox.Text + e.KeyChar.ToString());
}
If we didn't create a TextBox object, and instead created a TextBox each time we entered the method, then would we create a new event handler each time, and every event handled would be called, not just newly created. One problem though, is that the KeyPress event will not be fired when tab or return is pressed. One way to solve this problem is to listen to the cell's begin and end edit events. The CellBeginEdit event will be fired when the user start to edit the cell, e.g. by pressing F2, and the CellEndEdit is fired when user hits tab or return.

FooDataGridView.CellBeginEdit += new DataGridViewCellCancelEventHandler(FooDataGridView_CellBeginEdit);
FooDataGridView.CellEndEdit += new DataGridViewCellEventHandlerFooDataGridView_CellEndEdit);
void FooDataGridView_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
{
    System.Diagnostics.Debug.WriteLine("Start edit...");
}
void FooDataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
    System.Diagnostics.Debug.WriteLine("...end edit.");
}

Initialize NHibernate with cascade

The Hibernate lazy associations is a wonderful feature which minimize the database communication when loading (large) sets of data.
But sometimes you need to load the full dataset, and you don't want to set the lazy flag in the mapping files to false. The solution is to use the static method NHibernate.NHibernateUtil.Initialize(), but the problem is that this method doesn't cascade to associated objects, you only initialize the current object, and no underlying collection. The following is a snippet of code that initialize all collections, and their collections, and so on. 

protected void InitializeWithCascade(object rootObject)
{
  PropertyInfo[] propInfos = rootObject.GetType().GetProperties();

  foreach (PropertyInfo property in propInfos)
  {
   MethodInfo mi = property.GetGetMethod();
   System.Collections.ICollection collection = mi.Invoke(rootObject, null) as System.Collections.ICollection;

   if (collection != null)
   {
    // This is a collection
    System.Collections.IEnumerator iter = collection.GetEnumerator();
    while (iter.MoveNext())
    {
     // Initialize the collection
     NHibernate.NHibernateUtil.Initialize(iter.Current);

     // Iterate the set
     InitializeWithCascade(iter.Current);
    }
   }
  }
}

Saturday, August 29, 2009

Linker problems with Borland Builder

When building a project in Borland Builder (version 5) you can get a linker error such as:

[Linker Error] Fatal: Error detected (LME351)
[Linker Warning] Cannot reserve virtual memory at addr 461A0000 for -1703936 bytes (errcode 87)

This is a known bug in Borland Builder, and the reason is that the debug information file is too big. Every project with forms create a debug file (a *.tds file), when the size of this file exceeds roughly 32 MB the linker throws an error. The solution is to disable the debugging ability of forms with many controls:

  • Right-click a form in the "Project Manager", select "Edit local options..." and un-check the "Debug information" checkbox.

  • Delete the project's *.tds file and the vcl50*-files in the Borland installation directory (e.g. C:\Program Files\Borland\CBuilder5\Lib\vcl50.*).

  • Re-compile all files you have changed debug settings on.