Michael O'Dea-Jones

  • Bridge to Brisbane – Mouth Wide Shut!

    It's 6:45 AM on a Sunday morning. I am running up the Gateway Bridge with thousands of other runners. There are so many I have to go slow and watch my every step. All I can hear is the sound of shoes hitting the bitumen. The sky is blue, there is no wind. What a wonderful way to start Fathers day! I completed the Bridge to Brisbane 10 Km fun run in 60 minutes. That's 10 Km per hour and I did it breathing only through my nose! Not bad seeing as this was my first 10 Km run. I normally only run 4 Km's.

    Today I can't feel my legs!

    Wardy IT Bridge To Brisbane Team Photo

  • My SEAF Down Under Experience

    Have you ever swum in a creek or water hole that's dark and murky? Have you ever let yourself sink down into the water and watched as the sun's rays disappear through the green algae and dirt? Have you ever held your breath while the fear rises in you, the darkness surrounds you and the chill of the unknown depths creeps up your legs? I have, and to this day I still wonder how deep the water hole really was and if there was some prehistoric predator at the bottom licking its lips. Till last week designing and managing databases evoked in me similar feelings. The wonderful rush of adrenalin flowing from living on the edge mixed with the fear that something could have gone wrong.

    Last week (1st and 2nd of Sept) I attended the SQL Enterprise Architects Forum (SEAF) at the Sydney Convention and Exhibition Centre. I found it very enlightening. Finally I was getting reliable information from the experts of the SQL Server Customer Advisory Team (CAT) - part of Microsoft's SQL development team based in Redmond, California. It felt good. It was like scuba diving in the water hole with oxygen, powerful torches and diving buddies. Clustering, Log Shipping, Replication and Mirroring lost their mystery when explained in context. There were no scary monsters. I'm no guru and I was able to follow most of what was said. I felt a little like Sir Edmund Hillary who described his feelings as ones of "quiet satisfaction, almost a little bit of surprise" when he climbed Mt Everest. In my case the satisfaction and surprise came from the realisation that many of my thoughts were validated.

  • BindingNavigator + Validation = Grief

    I received a rather nasty shock to discover that you can't use the BindingNavigator Validating event to stop navigating to the next, previous, first or last record in a DataSource if there are validation errors on your Form. If you are using a DataGridView then set e.Cancel to true in the DataGridView's RowValidating event:

    private void form1Form_Load(object sender, EventArgs e)

    {

    this.jobTableAdapter.Fill(this.hermesDataSet.Job);

    form1DataSet.Job.ColumnChanging += new DataColumnChangeEventHandler(Job_ColumnChanging);

    jobDataGridView.RowValidating += new DataGridViewCellCancelEventHandler(jobDataGridView_RowValidating);

    }

     

    void Job_ColumnChanging(object sender, DataColumnChangeEventArgs e)

    {

    if (e.Column.ColumnName == "JobItem")

    {

    if (string.IsNullOrEmpty(e.ProposedValue.ToString()))

    {

    e.Row.SetColumnError(e.Column.ColumnName, "Item cannot be empty");

    }

    else

    {

    e.Row.SetColumnError(e.Column.ColumnName, string.Empty);

    }

    }

    }

     

    void jobDataGridView_RowValidating(object sender, DataGridViewCellCancelEventArgs e)

    {

    if (hermesDataSet.Job.HasErrors)

    {

    e.Cancel = true;

    }

    }

    If you are aren't using a DataGridView then set e.Cancel to true in the Control's (e.g. TextBox ) Validating event:

    private void taskStateNameTextBox_Validating(object sender, CancelEventArgs e)

    {

    if (string.IsNullOrEmpty(taskStateNameTextBox.Text))

    {

    taskStateErrorProvider.SetError(taskStateNameTextBox, "Name cannot be empty");

    e.Cancel = true;

    }

    else

    {

    taskStateErrorProvider.SetError(taskStateNameTextBox, string.Empty);

    }

    }

  • Windows Forms Videos

    If there is one consistent thing that I have learned about programming it is that there is always more to know. Being a visual learner, I gravitate towards videos. Here are some excellent videos on Windows Forms Controls, Data Binding and Windows Forms "under the hood":

    Visual C# Developer Center : Visual C# How Do I Video Series
    WindowsClient.Net : Windows Forms Videos

    The videos I found most interesting were:

    How to create a System Tray application using the NotifyIcon control
    How to call other applications using the Process control
    How to use the TreeView control
    How to use the WebBrowser control
    Databinding Data to User Interface Controls
    MSDN Webcast: How Microsoft Technology Works: Windows Forms (Level 200)

    Also I must say that I liked the web cast so much that I went to both of Jessica (aka jfo's) Blogs: MSDN, jfo's coding. In particular I found jfo's "Advice to myself, I wish I had had starting out" well worth the read.

    Mental note: "must learn WPF".

  • Double Buffering Windows Forms

    I'm working on an application where the presentation is very important and I want it to look great. I am overriding the Form's OnPaint() method so that I can create a Gradient background. I thought that I had done a fantastic job until I started to resize the Form and Noticed that it was flickering. Not to be outdone I researching the issue I came across a technique called Double Buffering that made a big difference.

    Double Buffering is the process whereby the Painting is done in memory first and then the result is copied to the screen. This is different from the default mode where the painting is done directly to the screen. Another contributing factor was that the Form was painting the Background and Foreground in two separate actions. These two actions can be combined to reduce flickering.

    In order to configure Double Buffering you need to apply three Styles to the Control and then force the Control to apply the new styles. Here are the three Styles:

    1. ControlStyles.AllPaintingInWmPaint
      1. Ignores Background Paint messages. The Control's Background and Foreground are painted at the same time.
    2. ControlStyles.UserPaint
      1. Configures the Control to execute the OnPaint and OnPaintBackground Methods.
    3. ControlStyles.DoubleBuffer
      1. Paints the Control in memory first and then copied the result to the screen.

    Invoke the Form's SetStyle() method to configure it for Double Buffering:

    protected override void OnLoad(EventArgs e)

    {

    base.OnLoad(e);

     

        // Double Buffer to reduce flickering

    this.SetStyle(ControlStyles.AllPaintingInWmPaint |

    ControlStyles.UserPaint |

    ControlStyles.DoubleBuffer, true);

     

    this.UpdateStyles();

    }

  • Why is Thread.CurrentPrincipal.Identity.Name empty?

    I am trying to get an audit trail going and want to record the user who created and modified the record in the database. I'm developing a .Net Windows Forms Application and assumed that the Current Principal's Identity was being set magically to the current user's identity. That's where my assumption was wrong. Apparently you have to set the Principal yourself. Here is the code that you can use to set the Application thread's Principal to the current User:

    Thread.CurrentPrincipal = new WindowsPrincipal(WindowsIdentity.GetCurrent());

    I added this line of code to the Main method in the Program class:

    static class Program

    {

    /// <summary>

    /// The main entry point for the application.

    /// </summary>

    [STAThread]

    static void Main()

    {

    Thread.CurrentPrincipal = new WindowsPrincipal(WindowsIdentity.GetCurrent());

    Application.EnableVisualStyles();

    Application.SetCompatibleTextRenderingDefault(false);

    Application.Run(new ProcessForm());

    }

    }

    For custom security situations you can create your own Generic Identity and set the current thread's Identity to it:

    string[] Roles = { "Employee" };

    GenericIdentity Identity = new GenericIdentity("Michael");

    GenericPrincipal Principal = new GenericPrincipal(Identity, Roles);

    Thread.CurrentPrincipal = Principal;