Category Archives: C#

Notes on C# / .NET

Reading from a SQL database

Self explanatory snippet


SqlConnection db = new SqlConnection(Properties.Settings.Default.ConnectionString);

            
try
{
   db.Open();
   SqlDataAdapter dataAdapter = new SqlDataAdapter("SELECT FirstName, LastName  FROM Contacts", db);

   DataTable dataTable = new DataTable();
   dataAdapter.Fill(dataTable);

   foreach(DataRow row in dataTable.Rows)
   {
      string firstName = row["FirstName"];
      string lastName  = row["LastName"];
   }
 
   db.Close(); 
   db.Dispose(); 
   db = null;0
}
catch (Exception e)
{
   System.Windows.Forms.MessageBox.Show(e.Message, "DB error", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);      
}
Lastest update in February 2012, inital post in February 2012

Playing a metafile

To show a metafile

metaFile = new Metafile(path);
e.Graphics.DrawImage(metaFile, clientRect);    
metaFile.Dispose(); 
metaFile = null;

Although this code shows the metafile, you may notice strange scaling problems. The metafile is being drawn ignoring the aspect ratio!

You can get the original size using the following code

MetafileHeader header = metaFile.GetMetafileHeader();
Rect metaRect = header.Bounds;

Use the metaRect to adjust the clientRect to get the same aspect ratio and the scaling will be fine.

Lastest update in February 2012, inital post in February 2012

Get the application folder

To get the path where the executable is located use the following code:

Path.GetDirectoryName(Application.ExecutablePath);

The returned path does not contain a trailing backslash.

To add a filename or mask use Path.Combine

Lastest update in February 2012, inital post in February 2012

Allow a UserControl to handle arrow keys

By default the arrow keys are processed by the form, to use them yourself override the following method.

 protected override bool IsInputKey(Keys keyData)
        {
            switch (keyData)
            {
                case Keys.Up:
                case Keys.Down:
                case Keys.Left:
                case Keys.Right:
                    return (true);
             }
            return base.IsInputKey(keyData);
        }

					
Lastest update in January 2012, inital post in January 2012

Prevent panels to be repainted on a form resize

To prevent lots of flicker during resizing disable the real-time resizing of the child controls.
To do so override both the Form OnResizeBegin and OnResizeEnd events.

protected override void OnResizeBegin(EventArgs e) 
{
    SuspendLayout();
    base.OnResizeBegin(e);
}

protected override void OnResizeEnd(EventArgs e) 
{
    ResumeLayout();
    base.OnResizeEnd(e);
}
Lastest update in January 2012, inital post in January 2012

Reduce flickering by disabling OnPaintBackground

When an entire control is painted (e.g. hosting a windowed directx control) it can be beneficial to override OnPaintBackground

In case of a windowed directx control double buffering is not possible, in other cases it may not be desirable.

When the background is not shown because it’s overlapped entirely, not drawing it all will speedup things and reduce flicker.

Add the following to the control to override.

protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs e)
{
}

Lastest update in December 2011, inital post in December 2011

Cannot modify the return value of System.Collections.Generic.List.this[int]‘ because it is not a variable

This error is shown when an attempt to assign a value to a property inside a struct.

e.g

System.Drawing.Point p = new Point();
p.X = 1; //legal of course

Listlist = new List();
list.Add(p);
list[0].X = 123; //Cannot modify the return value of System.Collections.Generic.List.this[int]‘ because it is not a variable

Remember structs are value types. They are processed like integers and only assigned as a whole.
Therefore when accessed from a list a copy of the struct is returned. Assigning to the copy is pointless, hence the error.

You can assign one member by using the following method

System.Drawing.Point p = list[0];
p.X = 123;
list[0] = p;

Lastest update in December 2011, inital post in December 2011

Calling a form control from a (worker)thread.

When using multiple threads controls on a form cannot be called directly. Doing so will throw an exception like ‘Cross-thread operation not valid: Control ‘dc’ accessed from a thread other than the thread it was created on.’

Fortunately there is a rather simple solution for this problem. Use the Invoke method to execute code in the GUI thread.

The invokemethod has the following prototype

public void Invoke(System.Delegate delegate);

For example: from a worker thread a button on a form (Form1)  must be pressed. From inside the thread use the following construct to perform it thread safe.

Invoke((MethodInvoker)delegate
{
   Button1.Click();
});

Invoke is a member of the Control class. To make it work use a control created in the same thread.  In the example above you can use Form1.Invoke() or Button1.Invoke() since they both are created in the same thread.

MethodInvoker is a default delegate definition. Its definition is  delegate void MethodInvoker;

External delegates:

Of course the delegate can be external as well, sometimes this is favorable to get cleaner code or if the delegate is frequently used.

delegate void ClickTheButton();
void clickTheButton()
{
   ...
}

Inside the method

ClickTheButton clickTheButtonDelegate = clickTheButton;
Invoke(clickTheButtonDelegate);

 

Delegates with parameters

Delegates can also be called with parameters . This uses the second form of Invoke()

public void Invoke(System.Delegate delegate, object [] args);

void clickTheButton(int value)
{
   ...
}

delegate void ClickTheButton(int);

Inside the method

 ClickTheButton clickTheButtonDelegate = clickTheButton;
 Invoke(clickTheButtonDelegate, new object[] {1});
Lastest update in October 2011, inital post in October 2011

Default fonts

A number of default system fonts can be found in System.Drawing.SystemFonts

Lastest update in July 2011, inital post in July 2011

Using a BackgroundWorker (thread)

The BackgroundWorker class can be used to start a background worker thread. Worker threads are typically used to perform lengthy task which would otherwise block the GUI or to perform simultaneous processing. Nowadays most computers have dual or quad core CPU’s Single thread application will not benefit from the additional cores.

Backround worker is a wrapper class for thread management. It can be dragged on the form in the designer or created in code. It is important to remember one BackgroundWorker instance can only serve one thread simultaneously!

Some code

void init()
{
  //Create a new instance, can also be done in the designer
   bw = new BackgroundWorker();

   //This event will be the main body of the thread
   bw.DoWork +=new DoWorkEventHandler(bw_DoWork);

   //Called when the thread ends gracefuly
   bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
   //Set to true to allow the thread to be canceled
   bw.CancellationPending = true;
   //Must be set to allow the DoWork event to call the ReportProgress method.
   bw.WorkerReportsProgress = true;

   //Called when the DoWork event calls ReportProgress
   bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);

   //Run the thread (DoWork event)
   bw.RunWorkerAsync();
}

The code above just setups the event handlers. There are other event handler for e.g. cancellation support.
The BackGroundWorker object is shared between the two threads.

The following function is called in the context of the thread which created the BackgroundWorker, typically the GUI thread.

void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
   MessageBox.Show("Progress " +  e.ProgressPercentage);
}

You can use the e.UserState which by default is the argument optionally passed to the RunWorkerAsync method. If the bw.ReportProgress is called with an extra argument this will be  the e.UserState object. It is strongly recommended to use a value type or to clone a reference object since it may be accessed simultaneously otherwise. The worker thread will NOT wait for this event to complete! (which is a good thing!)

The following event is called in the context of the creating thread also. It is called when the thread completes. But only when the threads exits itself not when it’s terminated forcefully.

void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
   MessageBox.Show("Complete");
}

This code runs in the worker thread, it is the actual threads body.

void bw_DoWork(object sender, DoWorkEventArgs e)
{
   BackgroundWorker bw = sender as BackgroundWorker;

   int t;
   for (t = 0; t < 100; t += 10)
   {
      if (e.CancellationPending)
      {
         e.Cancel = true;
         return;
      }

      bw.ReportProgress(t);
      System.Threading.Thread.Sleep(1000);
   }
}

The CancellationPending value is set by the CancelAsync method called from the creating thread.

Lastest update in June 2011, inital post in June 2011