December 14, 2008

Using Process

// Starting a windows program with Process
private void StartXXX()
{
 string dir = @"C:\CODE\blahblahblah\Server\XXX\bin";
 string exe = "XXX.exe";

 Process shellRunProcess = new Process();
 shellRunProcess.StartInfo.FileName = exe;
 shellRunProcess.StartInfo.WorkingDirectory = dir;
 shellRunProcess.StartInfo.Arguments = "-c";
 shellRunProcess.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
 shellRunProcess.Start();
}


// Terminating a process
private void TerminateXXX()
{
 // Remove the '.exe' extension when looking for the process
 Process[] processes = Process.GetProcessesByName("XXX"); 
 foreach (Process p in processes)
 {
  p.CloseMainWindow();
 }
}
When running a batch file or console type application, you can start if like so and have the output redirected to a control in your form. See this link for more information Launching A Console Process And Redirecting the Output
private void StartProcessWithoutWindow()
{
 Process process = new Process();
 process.StartInfo.UseShellExecute = false;
 process.StartInfo.RedirectStandardOutput = true;
 process.StartInfo.RedirectStandardError = true;
 process.StartInfo.CreateNoWindow = true;
 process.StartInfo.FileName = FileName;
 process.StartInfo.Arguments = Arguments;
 process.StartInfo.WorkingDirectory = WorkingDirectory;
 process.Start();
}

String Formatting

String Formatting Concise blog on c# string formatting Padding a number out with spaces or zeroes
public void TestNumberPaddingForString()
{
 int x = 1017;
 string msg = "->" + x.ToString("D8") + "<-";
 string msg2 = "->" + string.Format("{0:D8}", x) + "<-";
 Console.WriteLine(msg);
 Console.WriteLine(msg2);
 msg = "->" + x.ToString().PadLeft(8) + "<-";
 msg2 = "->" + string.Format("{0:D}", x).PadLeft(8) + "<-";
 Console.WriteLine(msg);
 Console.WriteLine(msg2);
 msg = "->" + x.ToString().PadRight(8) + "<-";
 msg2 = "->" + string.Format("{0}", x).PadRight(8) + "<-";
 Console.WriteLine(msg);
 Console.WriteLine(msg2);
}
Produces output:

->00001017<-
->00001017<-
->    1017<-
->    1017<-
->1017    <-
->1017    <-

Setting Form or Application Icon

To set the Icon of a WinForm application go to the Project properties and set the icon to use within the 'Application' tab. If you are using 'Icon and Manifest' option you can select the Icon into the text box. Setting a Form Icon Set this with the 'Icon' property of the form

Adding App Icon To Taskbar

Adding you WinForm app to the taskbar Some missing points 1. As it is, when minimized, the window will appear both in the taskbar (minimised) in the system tray. To fix this set the main form property 'ShowInTaskbar' to false;
public XXXForm()
{
 InitializeComponent();
 this.ShowInTaskbar = false;
}
Change the 'notifyIcon_DoubleClick':
private void notifyIcon_DoubleClick(object sender, EventArgs e)
{
 Show();
 ShowInTaskbar = true;
 WindowState = FormWindowState.Normal;
}
Also I prefer to override the resize rather than pick up an event
protected override void OnResize(EventArgs e)
{
 base.OnResize(e);
 // Hide the form when it is minimised
 if (FormWindowState.Minimized == WindowState)
  Hide();
}
I also added a menu timer to ensure that when the mouse leaves the context menu the menu dissappears after a short time (3 seconds). Aagh, next bit is for WPF based taskbar app.
using System.Windows.Threading;
...
public partial class AppMainWindow : Window
{
...
  private DispatcherTimer timer = null;
...
    public AppMainWindow ()
    {
      InitializeComponent();
...
      contextMenu = (ContextMenu)this.FindResource("NotifierContextMenu");
      contextMenu.Closed += new RoutedEventHandler(menu_Closed);
      contextMenu.Opened += new RoutedEventHandler(menu_Opened);
      CreateMenuTimer();
    }
...
  #region Timer

  private void CreateMenuTimer()
  {
    const int MILLISECOND = 10000;
    timer = new DispatcherTimer();
    // Disable (stop) it 
    timer.IsEnabled = false;
    // Set timer event interval
    timer.Interval = new TimeSpan((long)(3000 * MILLISECOND));
    // Timer events
    timer.Tick += new EventHandler(timer_Tick);
  }

  void timer_Tick(object sender, EventArgs e)
  {
    if (contextMenu.IsOpen)
    {
      if (contextMenu.IsMouseOver && contextMenu.IsMouseDirectlyOver)
      {
        contextMenu.IsOpen = false;
      }
    }
    else
    {
      timer.Stop(); 
    }
  }

  void menu_Opened(object sender, RoutedEventArgs e)
  {
    timer.Start();
  }

  void menu_Closed(object sender, RoutedEventArgs e)
  {
    timer.Stop(); 
  }

  #endregion Timer



November 11, 2008

Cool Commands

Cool commands for VS2008 OR Alternative or use CoolCommands here. 1. Unzip coolcommandsrtm.zip (ie: c:\coolcommands ) 2. Open VS 2005 command prompt 3. run c:\coolcommands\install.bat but download from here.

ForEach Implementation

This code shows in a simplistic manner how foreach is implemented using iterators. See the official explanantion or here for more details
// foreach Implementation
IEnumerable enumerable = (IEnumerable)targObject;
IEnumerator it = enumerable.GetEnumerator();
//it.Reset() NOT actuall called underneath.
while(it.MoveNext())
{
    DoSomething(it.Current);
}

Configuring Log4Net Programmatically

Configuring Log4Net Programmatically Set the logging level of the logger
public string LoggingLevel
{
 get
 {
  log4net.Repository.Hierarchy.Logger logger = (log4net.Repository.Hierarchy.Logger)m_log.Logger;
  return logger.Level.Name;
 }
 set
 {
  if (!string.IsNullOrEmpty(value))
  {
   log4net.Repository.Hierarchy.Logger logger = (log4net.Repository.Hierarchy.Logger)m_log.Logger;
   logger.Level = logger.Hierarchy.LevelMap[value];
  }
 }
}
Example configuring Appenders for a log
#region log4net

internal class LoggingConfigurer
{
    public static readonly string DefaultLayoutPattern = "%d [%t]%-5p %c [%x] - %m%n ";
    public static readonly string DefaultFileName = "XXXLog.txt";
    public static readonly string FileAppendarName = "XXXRFA";

    // Configure the logger programmatically. 
    public static void ConfigureLogging(ILog log)
    {
        bool isConfigured = log.Logger.Repository.Configured;
        if (!isConfigured)
        {
            // Setup RollingFileAppender
            RollingFileAppender rollingFileAppender = new RollingFileAppender();
            rollingFileAppender.Layout = new PatternLayout(DefaultLayoutPattern);
            rollingFileAppender.MaximumFileSize = "100KB";
            rollingFileAppender.MaxSizeRollBackups = 5;
            rollingFileAppender.RollingStyle = RollingFileAppender.RollingMode.Size;
            rollingFileAppender.AppendToFile = true;
            rollingFileAppender.File = DefaultFileName;
            rollingFileAppender.Name = FileAppendarName;
            rollingFileAppender.ActivateOptions(); // IMPORTANT, creates the file
            BasicConfigurator.Configure(rollingFileAppender);
#if DEBUG
            // Setup TraceAppender
            TraceAppender ta = new TraceAppender();
            ta.Layout = new PatternLayout(DefaultLayoutPattern);
            BasicConfigurator.Configure(ta);
#endif
        }
    }
}

#endregion log4net  
usage, when initialising your logger:
log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
LoggingConfigurer.ConfigureLogging(log);
Here is an example where the log file name is changed:
private static void RenameLogFile(string newLogFileName)
{
    var rfa = LogManager.GetRepository().GetAppenders().
         OfType<RollingFileAppender>().
         FirstOrDefault(appender => 
            appender.Name == LoggingConfigurer.FileAppendarName);
    if (rfa != null)
    {
        rfa.File = newLogFileName + ".txt";
        rfa.ActivateOptions();
    }
}

Delegating an Event Handler

// Say we have some event declared in one class
public event SomeStatusEventHandler SomeStatusEvent
{   // Delegate the event 'add' and 'remove' calls to the 'target' object
 add { this.target.SomeStatusEvent += value; }
 remove { this.target.SomeStatusEvent -= value; }
}
There is a sample of this in use in the Windows Service Class Example. Note that this syntax exposes an event for adding and removing event handlers but an event must be defined elsewhere that is to be exposed.
Say we have some private event declared in the same class:
private event SomeStatusEventHandler someStatusEvent;

public event SomeStatusEventHandler SomeStatusEvent
{   
 add { this.SomeStatusEvent += value; }
 remove { this.SomeStatusEvent -= value; }
}

Comparing Delegates, Anonymous Methods and Lambda Expressions

Here is a good link on this subject. Note the difference between a 'statement lambda' and an 'expression lambda'.
There are now 3 syntaxes for implementing delegates in C#. Here is the same code using the different syntax in each case:
1. Delegate
void StandardDelegateSample()
{
    ISomeResource[] resources =  someFacade.GetResources();
    ISomeResource target = Array.Find(resources, 
       new Predicate(FindTargetSomeResource));
}

// This method implements the test condition for the Find
// method.
private bool FindTargetSomeResource(ISomeResource res)
{
    return (res.Id == TARGET_ID);
}
2. Anonymous Method
void AnonymousMethodSample()
{
    ISomeResource[] resources =  someFacade.GetResources();
    ISomeResource target = Array.Find(resources, 
            delegate(ISomeResource res)
            {
                return (res.InformSourceId == TARGET_ID);
            }
    );
}
3. Lambda Expression
These are an even more shortened version of an anonymous delegate. The argument type can be missed out, the braces, and even the return statement. Like anonymous methods they can support variable capture from the encompassing method, ie. they can refer to the parameters or locals of the hosting method.
void LambdaExpressionSample()
{
  ISomeResource[] resources =  someFacade.GetResources();
  ISomeResource target = Array.Find(resources, 
    res => (res.InformSourceId == TARGET_ID) 
  );
}
Here are the 3 different forms of lambdas:
res => (res.Id == TARGET_ID) // simplest ('Expression Lambda') 
(ISomeResource res) => (res.Id == TARGET_ID) // specify parameter ('Expression Lambda')
(ISomeResource res) => { return (res.Id == TARGET_ID); } // Braces allow for multiple statements ('Statement Lambda')
However there is a gotcha with the use of anonymous methods (and lambda expressions?) so beware.
Code used to validate my lambda expressions:
public class LambdaExpressionTester
{
  public interface ISomeResource
  {
    int Id { get; set; }
              
    // ...
  }

  public class SomeResource : ISomeResource
  {
    public int Id { get; set; }
    //public string Name { get; set; } }
    // ...
  }

  private ISomeResource[] m_SomeResources = 
          new ISomeResource[] {
          new SomeResource{Id=1},
          new SomeResource{Id=4},
          new SomeResource{Id=11},
          new SomeResource{Id=43},
        };

  private static readonly int TARGET_ID = 11;

  public void LambdaExpressionSample()
  {
      ISomeResource[] resources = GetResources();
      ISomeResource target = Array.Find(resources, 
      res => (res.Id == TARGET_ID) 
      //(ISomeResource res) => (res.Id == TARGET_ID)
      //(ISomeResource res) => { return (res.Id == TARGET_ID); }
  );
  }

  private ISomeResource[] GetResources()
  {
      return m_SomeResources;
  }
}

Here is code to demonstrate all the forms of lambda expressions and anonymous delegates:
public void TestAllLambdaForms()
{
    int local = 3;

    // Implicitly typed lambda expression.
    Func<int, int> func1 = x => x+1;
            
    // Lambda expression with statement body.
    Func<int, int> func2 = x => { return x + 1; };

    // Lambda expression using formal parameters with expression body.
    Func<int, int> func3 = (int x) => x + 1;

    // Lambda expression using formal parameters with a statement body.
    Func<int, int> func4 = (int x) => { return x + 1; };

    // Lambda expression using multiple parameters.
    Func<int, int, int> func5 = (x, y) => x * y;

    // Lambda expression using multiple formal parameters.
    Func<int, int, int> func6 = (int x, int y) => x * y;

    // Lambda expression using with no parameters
    Action func7 = () => Console.WriteLine("blah blah blah");

    // Lambda expression accessing a local variable.
    Func<int, int> func8 = x => x * local;

    // Anonymous Method/Delegate with no parameter list.
    Func<int> func10 = delegate { return 1 + 1; };

    // Anonymous Method/Delegate method expression.
    Func<int, int> func11 = delegate(int x) { return x + 1; };

    // Anonymous Method/Delegate expression with 2 parameters.
    Func<int, int, int> func12 = delegate(int x, int y) { return x * y; };

    // Anonymous Method/Delegate accessing a local parameters.
    Func<int, int> func13 = delegate(int x) { return x * local; };

    Console.WriteLine("func1:" + func1.Invoke(1));
    Console.WriteLine("func2:" + func2.Invoke(1));
    Console.WriteLine("func3:" + func3.Invoke(1));
    Console.WriteLine("func4:" + func4.Invoke(1));
    Console.WriteLine("func5:" + func5.Invoke(2, 2));
    Console.WriteLine("func6:" + func6.Invoke(2, 2));
    Console.Write("func7:"); func7.Invoke();
    Console.WriteLine("func8:" + func8.Invoke(1));
    Console.WriteLine("func10:" + func10.Invoke());
    Console.WriteLine("func11:" + func11.Invoke(1));
    Console.WriteLine("func12:" + func12.Invoke(2, 2));
    Console.WriteLine("func13:" + func13.Invoke(1));
}
Here is the output:
func1:2
func2:2
func3:2
func4:2
func5:4
func6:4
func7:blah blah blah
func8:3
func10:2
func11:2
func12:4
func13:3

Calling WaitOne With A TimeOut

... 
AutoResetEvent finishedEvent = null;
...
finishedEvent = new AutoResetEvent(false);
try
{
 DoSomethingOnAnotherThread()
 // Wait until the 'finishedEvent' is 'Set()'
 // to tell us that the job is complete
 if (finishedEvent.WaitOne(TWENTY_SECONDS, false))
 {
  OnSuccess();
 }
 else // Timed out before event was called
 {
  OnTimedOut();
 }
}
finally
{
 finishedEvent.Close();
 finishedEvent = null;
}        

Exceptions

Top 10 Tips for Exception Handling in C#
Exception Types
Exception ClassCause
SystemExceptionA failed run-time check;used as a base class for other.
AccessExceptionFailure to access a type member, such as a method or field.
ArgumentExceptionAn argument to a method was invalid.
ArgumentNullExceptionA null argument was passed to a method that doesn't accept it.
ArgumentOutOfRangeExceptionArgument value is out of range.
ArithmeticExceptionArithmetic over - or underflow has occurred.
ArrayTypeMismatchExceptionAttempt to store the wrong type of object in an array.
BadImageFormatExceptionImage is in the wrong format.
CoreExceptionBase class for exceptions thrown by the runtime.
DivideByZeroExceptionAn attempt was made to divide by zero.
FormatExceptionThe format of an argument is wrong.
IndexOutOfRangeExceptionAn array index is out of bounds.
InvalidCastExpressionAn attempt was made to cast to an invalid class.
InvalidOperationExceptionA method was called at an invalid time.
MissingMemberExceptionAn invalid version of a DLL was accessed.
NotFiniteNumberExceptionA number is not valid.
NotSupportedExceptionIndicates sthat a method is not implemented by a class.
NullReferenceExceptionAttempt to use an unassigned reference.
OutOfMemoryExceptionNot enough memory to continue execution.
StackOverflowExceptionA stack has overflown.

October 11, 2008

Exposing .NET assembly as a COM object.

Exposing .NET Assemblies as COM components. - Trouble is that he suggest placing the .NET component in the GAC. The problem with this is that the assembly and all its dependencies must then have a strong name! Better expose on deploying .NET Assemblies as COM components Sourcing .Net events for COM Sinks Really Raising Events Handled by a C++ COM Sink Sinking events from managed code in unmanaged C++ This is the simple method that avoids the use of the GAC. In the 'AssemblyInfo.cs' file add the following:
// Setting ComVisible to false makes the types in this assembly not visible 
// to COM components.  If you need to access a type in this assembly from 
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(true)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("f23114e6-5754-4793-b2c2-8cbe299421ad")]
The .Net component should have the following form:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace TestNETComComponent
{
   // Declare the interface
   [ComVisible(true), Guid("23661D34-4D5E-42e7-9992-CA64923E2221")]
   // No IDIspatch, only the simplest IUknown derived COM interface
   [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
   public interface ISomeInterface
   {
      int DoSomething();
      int DoSomethingElse(string arg);
   }

   // Need a class to implement the interface 
   [Guid("2AD6213C-0632-450b-8742-224913943C87")]
   [ProgId("Test.TestNETComComponent")]
   [ClassInterface(ClassInterfaceType.None)]
   public class TestNETCom : ISomeInterface
   {
      #region ISomeInterface Members

      public int  DoSomething()
      {
         Debug.WriteLine("TestNETCom.DoSomething()");
         return 1;
      }

      public int DoSomethingElse(string arg)
      {
     Debug.WriteLine("TestNETCom.DoSomethingElse() - " + m_SomeString);
         return 1;
      }

      #endregion
   }
}
Use this command line to register the assembly with COM and create the type library: regasm.exe /codebase /tlb TestNETComponent.dll To unregister the assembly: regasm.exe /unregister TestNETComponent.dll

October 7, 2008

Batch File To Clean A Build

Batch file to clean a development environment Add /f to the 'del ...' statements to force deletion of readonly files as well
cd "c:\SomeDevPath"
del /q /s *.exe
del /q /s *.dll
del /q /s *.pdb
del /q /s *.cache
del /q /s *.resources
del /q /s *.proj.user
pause

Interlocked.CompareExchange Usage

To protect an area of code without blocking:
int m_InUse = 0;
...
// Only allow one thread to enter but do not queue up other threads
if (System.Threading.Interlocked.CompareExchange(ref m_InUse, 1, 0) == 0)
{  
  DoSomething();
  // No longer in use, reset it.
  // NOTE: Interlocked.Exchange not needed here as this is a write of a literal value!
  m_InUse = 0;
} 
Is semantically the equivalent of:
static object Lock = new System.Object();
public int CompareExchange(ref int loc, int value, int comp)
{
    Monitor.Enter(Lock);
    int ret = loc;
    if (ret == comp)  
        loc = value;
    Monitor.Exit(Lock);
    return ret;
}
although it does NOT use Monitors internally.
There is a good example of this being used in the Windows Service Class Example

Boxing and Interfaces

public static void TestBoxing()
{
    // Create value
    SomeValueType myval = new SomeValueType();
    myval.X = 123;
    Debug.WriteLine("1. myval: " + myval.ToString());

    // box it
    object obj = myval;
    Debug.WriteLine("2. boxed: " + obj.ToString());

    // modify the contents in the box.
    ISomeValue iface = (ISomeValue)obj;
    iface.X = 456;
    Debug.WriteLine("3. After interface call: " + obj.ToString());

    // unbox it and see what it is.
    SomeValueType newval = (SomeValueType)obj;
    Debug.WriteLine("4. unboxed: " + newval.ToString());
    Debug.WriteLine("5. myval: " + myval.ToString());
    ((ISomeValue)myval).X = 789;
    Debug.WriteLine("6. myval: " + myval.ToString() + " obj: " + obj.ToString());
    ((ISomeValue)obj).X = 789;
    Debug.WriteLine("7. obj: " + obj.ToString());
    myval = (SomeValueType)obj;
    Debug.WriteLine("8. myval: " + myval.ToString());
}
Output:
1. myval: X=123
2. boxed: X=123
3. After interface call: X=456
4. unboxed: X=456
5. myval: X=123
6. myval: X=123 obj: X=456
7. obj: X=789
8. myval: X=789
Conclusion: To use an interface to modify a value type you must explicitly box and unbox it.

Invoke/BeginInvoke On A GUI Thread

Good article on BeginInvoke and Invoke differences
Here is a code template for it. On the GUI class (form or control derived object):
  private delegate void DataChanged(Object Sender, BindingEventArgs Args);

  private void HandleDataChanged(Object
Sender, BindingEventArgs Args)
  {
    // If this delegate is invoked on another thread
    if (this.InvokeRequired)
    {
      // Asynchronously call THIS method later
      // but this time on our own GUI thread
      // BeginInvoke translates to a PostMessage call on
      // our window.
      BeginInvoke(new DataChangedDelegate(HandleDataChanged),
 new object[] { Sender, Args });
    }
    else // when the method is invoked on the GUI thread
    { // Update our forms/controls as required
      UpdateGui(Args);
    }
  }
Simpler form of the InvokeRequired/BeginInvoke or Invoke pattern using the MethodInvoker
private void OnHandleDataChanged()
{
  // If this delegate is invoked on another thread
  if (this.InvokeRequired)
  {
    // Asynchronously call THIS method later
    // but this time on our own GUI thread
    // BeginInvoke translates to a PostMessage call on
    // our window.
    // Invoke maps to a SendMessage call, it will BLOCK 
    // the calling thread until finished
    BeginInvoke/Invoke(new MethodInvoker(HandleDataChanged));
  }
  else // when the method is invoked on the GUI thread
  { 
    // Update our forms/controls as required
  }
}
Simplest InvokeRequired Pattern, again this is within the GUI object:
// Define the delegate
private delegate void SomeDelegate(string arg1, int arg2);
// or (easier) use Action<string, int>, see below

private void HandleDataChanged(string arg1, int arg2)
{
  // IF this delegate is invoked on another thread
  if (this.InvokeRequired)
  { // THEN Call it again asynchronously on the GUI thread 
    this.BeginInvoke(
     new Action<string, int>(HandleDataChanged),
     // Make sure the number of args here matches the number 
     // of args in the delegate!
     new object[] { arg1, arg2 });
    return;
  }
  // From this point onwards we are definitely on the GUI thread again
  
  // Update our forms/controls as required
  ...    
}

BackgroundWorker Usage

Better Sample BackgroundWorker usage Create a class that derives from the BackgroundWorker class that implements the threading routine by overriding the OnDoWork method rather than implementing the work method using the 'DoWork' event. The class user only needs to hook up the 'ProgressChanged' and 'RunWorkerThread' completed events. This style is more object orientated than the conventional usage where the worker code is specified in the 'DoWork' event. All the routines executed on the background thread can be separated from the rest of the code and encapsulated in the worker class. This makes it easier to see what shared data the threading routine is accessing.
// This sample deletes all the 'bin' and 'obj' directories 
// under a specified directory
internal class CleanDirWorker : BackgroundWorker
{
    string m_TargetDirectory = string.Empty;

    float total = 0;
    float count = 0;


    public CleanDirWorker() :
        base()
    {
        this.WorkerReportsProgress = true;
    }

    public string TargetDirectory
    {
        get { return m_TargetDirectory; }
        set { m_TargetDirectory = value; }
    }

    private void CleanDirectories(string dirTarget)
    {
        if (Directory.Exists(dirTarget))
        {
            DirectoryInfo diTarg = new DirectoryInfo(dirTarget);
            DirectoryClean(diTarg);
        }
        else
        {
            string msg = "Directory \'" + dirTarget + "\' does not exist";
        }
    }

    private void DirectoryClean(DirectoryInfo diTarg)
    {
        DirectoryInfo[] binDirs = diTarg.GetDirectories("bin", 
    SearchOption.AllDirectories);
        DirectoryInfo[] objDirs = diTarg.GetDirectories("obj", 
    SearchOption.AllDirectories);
        total = binDirs.Length + objDirs.Length;
        this.ReportProgress(10);
        DeleteDirs(binDirs);
        DeleteDirs(objDirs);
    }

    private void DeleteDirs(DirectoryInfo[] dis)
    {
        foreach (DirectoryInfo di in dis)
        {
            try
            {
                Debug.WriteLine("Deleting \'" + di.FullName + "\'");
                //di.Delete(true);
                count = count + 1.0f;
                int progress = 10 + (int)Math.Round(0.9f * total / (total - count));
                this.ReportProgress(progress);
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Exception occured trying to delete \'" + 
    di.FullName + "\' :" + ex.ToString());
            }
        }
    }

    protected override void OnDoWork(DoWorkEventArgs e)
    {
        try
        {
            if (!string.IsNullOrEmpty(m_TargetDirectory))
            {
                //DirectoryCleaner dc = new DirectoryCleaner();
                CleanDirectories(m_TargetDirectory);
            }
        }
        catch (Exception ex)
        {
            Trace.WriteLine("Exception occured :" + ex.ToString());
        }
    }
}
To use it we use the events to monitor the progress of the worker thread and to find out when the worker thread has completed
// NOTE pbClean is a progress bar in this sample 

private void button_Click(object sender, RoutedEventArgs e)
{
    if (!string.IsNullOrEmpty(tbCleanTarg.Text))
    {
        AsyncCleanDirectories();
    }
}

#region CleanDirWorker Usage
CleanDirWorker m_CleanDirWorker = null;

private void InitializeCleanWorkerDir()
{
    m_CleanDirWorker = new CleanDirWorker()
    m_CleanDirWorker.RunWorkerCompleted += new
         RunWorkerCompletedEventHandler(m_CleanDirWorker_RunWorkerCompleted);
    m_CleanDirWorker.ProgressChanged += 
      new ProgressChangedEventHandler(m_CleanDirWorker_ProgressChanged);
}

private void TerminateCleanWorkerDir()
{
 m_CleanDirWorker.Dispose();
}

private void AsyncCleanDirectories()
{
    if (m_CleanDirWorker == null)
    {
 InitializeCleanWorkerDir();
        pbClean.Value = 0;
        m_CleanDirWorker.TargetDirectory = tbCleanTarg.Text;
        m_CleanDirWorker.RunWorkerAsync(null);
    }
}

void m_CleanDirWorker_ProgressChanged(
  object sender, 
  ProgressChangedEventArgs e)
{
    pbClean.Value = e.ProgressPercentage;
}

private void m_CleanDirWorker_RunWorkerCompleted(
  object sender,
  RunWorkerCompletedEventArgs e)
{
    TerminateCleanWorkerDir();
}
#endregion CleanDirWorker Usage

September 7, 2008

Posting Windows Messages Accross Processes

public class WinMessagePoster
{
  [DllImport("user32")]
  public static extern bool PostMessage(IntPtr hwnd, int msg, 
          IntPtr wparam, IntPtr lparam);

  [DllImport("user32")]
  public static extern int RegisterWindowMessage(string message);

  // this class just wraps some Win32 stuffthat we're going to use
  public const int HWND_BROADCAST = 0xffff;

  public static readonly int WM_APP_MYMESSAGE = 
                                 RegisterWindowMessage("WM_APP_MYMESSAGE");

  public void PostWinMessageToAnotherApp()
  {
    Process[] processes = Process.GetProcessesByName("ApplicatioName");
    foreach (Process p in processes)
    {
      IntPtr pFoundWindow = p.MainWindowHandle;
      PostMessage(pFoundWindow, "WM_APP_MYMESSAGE", IntPtr.Zero, IntPtr.Zero);
    }
  }
}
In the application that receives the windows message
// In .exe Main Form
#region Detect Custom Windows Message

public static readonly int WM_APP_MYMESSAGE = 
  RegisterWindowMessage("WM_APP_MYMESSAGE");

[DllImport("user32")]
public static extern int RegisterWindowMessage(string message);

protected override void WndProc(ref Message m)
{
  if (m.Msg == WM_APP_MYMESSAGE)
  {
    DoSomething();
  }
  base.WndProc(ref m);
}

#endregion Detect Custom Windows Message

GPS Serial Port Provider

For the actual serial port provider we have a base class. This takes care of all the serial port side of things
using System;
using System.Collections.Generic;
using System.Text;
using System.IO.Ports;
using System.Diagnostics;

namespace GpsTest
{
  public abstract class SerialPortGpsProviderBase : IGpsDataProvider
  {
    /// <summary>
    /// Fire this event when A GPS line of data has been received
    /// </summary>
    public event GpsDataReceivedEventHandler GpsDataReceived;

    #region Attributes

    protected SerialPort comPort = new SerialPort();

    #endregion

    public SerialPortGpsProviderBase()
    {
    }

    ~SerialPortGpsProviderBase()
    {
      Dispose(false);
    }

    #region IDisposable Members

    private bool m_disposed = false;

    public void Dispose()
    {
      Dispose(true);
      GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
      if (!m_disposed)
      {
        if (disposing)
        {
          // Dispose managed resources
        }

        // Dispose unmanaged resources
        comPort.Dispose();
      }
      m_disposed = true;
    }

    #endregion

    public bool IsOpen()
    {
      return comPort.IsOpen;
    }

    public void Open()
    {
      //set up the delegate used to read data in.......
      comPort.DataReceived += new SerialDataReceivedEventHandler(comPort_DataReceived);

      try
      {
        //finally open the port....
        comPort.Open();
        Trace.WriteLine("Com port " + comPort.ToString() + " Open=" + comPort.IsOpen.ToString());
      }
      catch (System.Exception ex)
      {
        Trace.WriteLine(DateTime.Now.ToString() + 
           ": Failed to open COM port with exception: " + ex.Message);
      }
    }

    protected abstract void comPort_DataReceived(object sender, 
            SerialDataReceivedEventArgs e);

    protected void FireGpsDataReceived(string data)
    {
      try
      {
        if ((data.Length > 0) &&
            (GpsDataReceived != null))
        {
          GpsDataReceived(this, new GpsDataLineEventArgs(data));
        }
      }
      catch (System.Exception ex)
      {
        Trace.WriteLine(DateTime.Now + 
            ": Failed to extract GPS data in comPort_DataReceived: " +
             ex.Message);
      }
    }


    public void Close()
    {
      try
      {
        //check we have a valid COM port to close...
        if (comPort.IsOpen)
        {
          comPort.Close();
          Debug.WriteLine("Com port " + comPort.ToString() + " CLOSED");
        }
      }
      catch (System.Exception ex)
      {
        Trace.WriteLine(DateTime.Now.ToString() + 
                ": Failed to close COM port with exception: " +
                ex.Message);
      }
    }
  }

}

The actual provider just implements the code to read the data and parse it
using System;
using System.Collections.Generic;
using System.Text;
using System.IO.Ports;
using System.Diagnostics;

namespace GpsTest
{

  // First simple provider 
  public class GpsSerialPortDataProvider : SerialPortGpsProviderBase
  {
    #region Attributes

    private const string comPortName = "COM14"; 
    private const int baudRate = 4800;

    #endregion

    public GpsSerialPortDataProvider()
    {
      //set up the com port settings.....
      comPort.PortName = comPortName;
      comPort.BaudRate = baudRate;
      comPort.Parity = Parity.None;
      comPort.StopBits = StopBits.One;
      comPort.DataBits = 8;
      comPort.Handshake = Handshake.None;
      comPort.ReadTimeout = 1000;
      comPort.NewLine = "\r\n";
    }

    ~GpsSerialPortDataProvider()
    {
      Dispose(false);
    }

    protected override void comPort_DataReceived(
      object sender, 
      SerialDataReceivedEventArgs e)
    {
      //Read a line of GPS data (each is sent with a \r\n at the end)
      try
      {
        string data = comPort.ReadLine();
        FireGpsDataReceived(data);
      }
      catch (System.Exception ex)
      {
        Trace.WriteLine(DateTime.Now + 
          ": Failed to extract GPS data in comPort_DataReceived: "
          + ex.Message);
      }
    }

  }

}
Due to a driver fault on the device we were using we could not read the data a line at a time. We had to clear the buffer out every time we read it, so here is the alternative provider
using System;
using System.Collections.Generic;
using System.Text;
using System.IO.Ports;
using System.Diagnostics;

namespace GpsTest
{

public class GpsSerialPortDataProvider3 : SerialPortGpsProviderBase
{

  #region Attributes

  private const string comPortName = "COM14";
  private const int baudRate = 4800;

  #endregion

  public GpsSerialPortDataProvider3()
  {
    //Setup the COM port
    comPort.PortName = comPortName;
    comPort.BaudRate = baudRate;

    //set up the other settings.....
    comPort.Parity = Parity.None;
    comPort.StopBits = StopBits.One;
    comPort.DataBits = 8;
    comPort.Handshake = Handshake.None;
    comPort.ReadTimeout = 1000;
    comPort.ReceivedBytesThreshold = 256;
  }

  ~GpsSerialPortDataProvider3()
  {
    Dispose(false);
  }

  private string buffer = "";
  private object bufferLock = new object();

  protected override void comPort_DataReceived(object sender, 
           SerialDataReceivedEventArgs e)
  {
    //Read a line of GPS data (each is sent with a \r\n at the end)
    try
    {
      // Read out everything in the buffer
      string data = comPort.ReadExisting();
      if (data.Length > 0)
      {
        string ready = string.Empty;
        lock (bufferLock)
        {
          buffer += data;
          // Do we have any complete lines in the buffer
          int ix = buffer.LastIndexOf("\r\n");
          if (ix >= 0)
          {
            // Remove all the complete lines
            ready = buffer.Remove(ix);
            // Truncate the buffer any incomplete data at the end
            buffer = buffer.Remove(0, ix + 2);
          }
        }
        if (ready.Length > 0) // found some complete lines
        {
          // Extract them
          string[] lines = ready.Split(new string[] { "\r\n" },
               StringSplitOptions.RemoveEmptyEntries);
          foreach (string line in lines)
          {
            // Invoke the GpsDataReceived event with the complete line
            FireGpsDataReceived(line);
          }
        }

      }
    }
    catch (System.Exception ex)
    {
      Trace.WriteLine(DateTime.Now.ToString() + 
           ": Failed to extract GPS data in comPort_DataReceived: " +
            ex.Message);
    }
  }

}

}

GPS Monitoring Test Provider

Here is a test provider
using System;
using System.Collections.Generic;
using System.Text;
using System.Timers;
using System.Diagnostics;
using System.IO;

namespace GpsTest
{
  class GpsTestProvider : IGpsDataProvider, IDisposable
  {
    Timer timer = new Timer();
    int index = 0;
    string[] sampleData = new string[]
      {
          "$GPRMC,135150.000,A,5106.7058,N,00123.8886,W,4.07,192.74,250808,,,A*74",
          "$GPRMC,135151.000,A,5106.7044,N,00123.8903,W,4.75,210.87,250808,,,A*74",
          "$GPRMC,135152.000,A,5106.7037,N,00123.8916,W,3.52,212.41,250808,,,A*7D",
          "$GPRMC,135153.000,A,5106.7033,N,00123.8927,W,2.88,208.03,250808,,,A*71",
          "$GPRMC,135154.000,A,5106.7030,N,00123.8928,W,2.72,205.69,250808,,,A*7E",
          "$GPRMC,135155.000,A,5106.7024,N,00123.8942,W,2.70,211.83,250808,,,A*75",
          "$GPRMC,135156.000,A,5106.7021,N,00123.8945,W,1.60,188.74,250808,,,A*7D",
          "$GPRMC,135157.000,A,5106.7017,N,00123.8945,W,1.21,168.54,250808,,,A*70",
      };


    public GpsTestProvider()
    {
      const string sampleDataFile = "GPSTestData.txt";
      if (File.Exists(sampleDataFile))
      {
        sampleData = File.ReadAllLines(sampleDataFile);
      }
    }

    #region Dispose Implementation

    // Use C# destructor syntax for finalization code.
    ~GpsTestProvider()
    {
      Debug.Assert(false, "This object was not disposed of");
      Dispose(false);
    }

    private bool m_Disposed = false;

    //Implement IDisposable.
    public void Dispose()
    {
      Dispose(true);
      GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
      if (m_Disposed)
        return;

      if (disposing)
      {
        // TODO: cleanup managed resources in GpsTestProvider
      }
      Close();
      timer.Dispose();

      m_Disposed = true;
    }

    #endregion Dispose Implementation


    #region IGpsDataProvider Members

    public void Close()
    {
      timer.Stop();
      timer.Enabled = false;
    }

    public event GpsDataReceivedEventHandler GpsDataReceived;

    public void Open()
    {
      timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
      timer.Interval = 100;
      timer.Start();
      timer.Enabled = true;
    }

    public bool IsOpen()
    {
      return timer.Enabled;
    }
    #endregion

    void timer_Elapsed(object sender, ElapsedEventArgs e)
    {
      if (GpsDataReceived != null)
      {
        GpsDataReceived(this, new GpsDataLineEventArgs(sampleData[index]));
        index = (index + 1) % sampleData.Length;
      }
    }

  }
}

September 2, 2008

GPS Monitoring

Here is the structure view of the Gps Design: Define the provider interface
  public interface IGpsDataProvider
  {
    void Close();
    event GpsDataReceivedEventHandler GpsDataReceived;
    void Open();
    bool IsOpen();
  }
Later we can derive a test provider Here are the event helpers

    public delegate void GPSDataEventHandler(object sender, GPSDataEventArgs e);

    public class GPSDataEventArgs : EventArgs
    {
        #region Members
        private GPSFix m_FixState = GPSFix.NoFix;
        private double m_Longitude = 0;
        private double m_Latitude = 0;
        private double m_SpeedMetresPerSec = 0;
        private double m_BearingDegrees = 0;
        #endregion

        #region Properties
        public GPSFix FixState { get { return m_FixState; } }
        public double Longitude { get { return m_Longitude; } }
        public double Latitude { get { return m_Latitude; } }
        public string CoordinateSystem { get { return GpsListener.coordindateSystem; } }
        public double SpeedMetresPerSec { get { return m_SpeedMetresPerSec; } }
        public double BearingDegrees { get { return m_BearingDegrees; } }
        #endregion

        #region Constructor
        public GPSDataEventArgs(GPSFix a_FixState, double a_Longitude, 
                  double a_Latitude, double a_SpeedMetresPerSec, 
                  double a_BearingDegrees)
        {
            m_FixState = a_FixState;
            m_Longitude = a_Longitude;
            m_Latitude = a_Latitude;
            m_SpeedMetresPerSec = a_SpeedMetresPerSec;
            m_BearingDegrees = a_BearingDegrees;
        }
        #endregion

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder(128);
            sb.Append(" FixState=" + m_FixState.ToString());
            sb.Append(" Long=" + m_Longitude.ToString());
            sb.Append(" Long=" + m_Longitude.ToString());
            sb.Append(" Lat=" + m_Latitude.ToString());
            sb.Append(" Speed=" + m_SpeedMetresPerSec.ToString());
            sb.Append(" Bearing=" + m_BearingDegrees.ToString());
            return sb.ToString();
        }
    }

    public delegate void GpsDataReceivedEventHandler(object sender,
              GpsDataLineEventArgs e);

    public class GpsDataLineEventArgs : EventArgs
    {
        #region Members
        private string m_Data = string.Empty;
        #endregion

        #region Properties

        public string Data
        {
            get { return m_Data; }
            set { m_Data = value; }
        }

        #endregion

        #region Constructor
        public GpsDataLineEventArgs(string data)
        {
            m_Data = data;
        }
        #endregion
    }
Here is the Listener:

August 16, 2008

Regular Expressions

For matching purposes:
? = 0 or 1 match
* = 0..n matches
+ = 1..n matches
{m,n} = 'm..n' matches where 'm' and 'n' are digits
{n} = exactly 'n' matches where 'n' is a digit
\d = numeric digit

This example matches a United Kingdom postcode:
using System.Text.RegularExpressions;
...
const string PostCodeRegEx = @"(GIR0AA|[A-PR-UWYZ]([0-9]{1,2}|" + 
  "([A-HK-Y][0-9]|[A-HK-Y][0-9]([0-9]|[ABEHMNPRV-Y]))|" +
  "[0-9][A-HJKS-UW])[0-9][ABD-HJLNP-UW-Z]{2})";
public bool IsPostCode(string postCode)
{
    postCode = postCode.Trim().Replace(" ", string.Empty);
    bool res = Regex.IsMatch(postCode, PostCodeRegEx);
    return res;
}
This example Matches a SID:
using System.Text.RegularExpressions;
...
result = string.Empty;
const string SID_PATTERN = @"(\w-\d-\d-\d{2}-\d+-\d+-\d+)";
Regex reg = new Regex(SID_PATTERN);
MatchCollection mc = reg.Matches(sid);
if (mc.Count > 0)
{
    result = mc[0].Value;
}

Enums

See this blog entry for information and example on the use of DescriptionAttribute with Enums

This example uses an ComboBox to store the enumeration values as strings Preparing the Combobox
foreach (XXXEnum entry in Enum.GetValues(typeof(XXXEnum)))
    comboBox.Items.Add(entry);
OR
cbLoggingLevel.Items.AddRange(Enum.GetValues(typeof(XXXEnum)));

// Making an initial selection
comboBox.SelectedIndex = comboBox.Items.Count - 1; // Select the last one
OR
comboBox.SelectedIndex = 0; // Select the first
Converting to and from a string
//To convert an enum to a string use:
MyComboBox.SelectedItem = m_Object.XXXEnum .ToString();

//The reverse process is a little more complicated
XXXEnum gc = (XXXEnum ) Enum.Parse(typeof(XXXEnum ),
                        MyComboBox.SelectedItem.ToString(), true);
There is a better way to parse the enum from a string that I found here.:
public static class StringExtender
{
  public static TEnum ParseToEnum<TEnum>(this string name)
    where TEnum : struct
  {
    if (false == typeof(TEnum).IsEnum)
      throw new NotSupportedException(typeof(TEnum).Name + " must be an Enum");

    string trimmed = name.Trim();
    
    if (false == Enum.IsDefined(typeof(TEnum), trimmed))
      throw new ArgumentException(string.Format(
         "\'{0}\' is not defined in type of enum {1}", trimmed, typeof(TEnum).Name));

    return (TEnum)Enum.Parse(typeof(TEnum), trimmed);
  }
}
alternatively use the TryParse method.
public class EnumTester
{
  public enum DescriptionsEnum
  {
    None,
    AddOn,
    SnapOn,
    Adjacent,
    Fixed,
  };

  public void ParseEnumFromStringTest()
  {
    DescriptionsEnum test = DescriptionsEnum.None;
    test = StringExtender.ParseToEnum<DescriptionsEnum>("Adjacent");
    Debug.Assert(test == DescriptionsEnum.Adjacent);
    test = "Fixed".ParseToEnum<DescriptionsEnum>();
    Debug.Assert(test == DescriptionsEnum.Fixed);
    test = "   SnapOn  ".ParseToEnum<DescriptionsEnum>();
    Debug.Assert(test == DescriptionsEnum.SnapOn);
    //test = "      snapon    ".ParseToEnum<DescriptionsEnum>(); // FAILS!
    //Debug.Assert(test == DescriptionsEnum.SnapOn);

    bool success = Enum.TryParse<DescriptionsEnum>("Adjacent", out test);
    Debug.Assert(test == DescriptionsEnum.Adjacent);
    success = Enum.TryParse<DescriptionsEnum>("fixed", true, out test);
    Debug.Assert(test == DescriptionsEnum.Fixed);
    success = Enum.TryParse<DescriptionsEnum>("  fixed     ", true, out test);
    // Line below succeeds. - TryParse is more robust so use it instead!
    Debug.Assert(test == DescriptionsEnum.Fixed); 
  }
}

Iterating through enumerated types:
foreach (XXXEnum entry in Enum.GetValues(typeof(XXXEnum)))
{
    Debug.WriteLine(entry.ToString() + "=" + ((int)entry).ToString());                
}
See Flags Based Enumerated Types

Color

To create a color with a given RGB value use
Color color = Color.FromRGB(0xf1, 0xee, 0x45);
//otherwise
Color.Red, ...

Random Number Generator

Random class in .Net is part of System namespace
//Declare an object
Random randomNumberGenerator = new Random();
random.NextDouble() //to get the next random number between 0.0 and 1.0;
random.Next() // to get the next random positive integer number
// to get the next random integer, x where  'upper' <= x  < 'lower'
random.Next(lower, upper) 
Byte[] b = new Byte[10];
random.NextBytes(b); to set an array of bytes

//To set a seed for the random number generator
int seed = 137;
System.Random randomNumberGenerator = new System.Random(seed);

August 10, 2008

Ownerdraw ListView

Msdn: On Msdn Find this article with Google TODO: Add our code here

Standard Delegates And Events

Standard event handler, no delegate definition necessary.
public event EventHandler xxxChanged;
Standard delegate handler, no delegate definition necessary.
using System;
//public delegate void Action()
Action xxxDelegate = new Action(xxxMethod);

public delegate TResult Func()
//Use it with anonymous methods:
Func methodCall = delegate() { return xxx.MethodReturningABool(); };
//There are other Func overloads, eg:
//public delegate TResult Func()
Func convert = delegate(int s)
         { return i.ToString() }; 

OR
// definition: public delegate void MethodInvoker()
using  System.Windows.Forms;
...
MethodInvoker xxxDelegate = new MethodInvoker(xxxMethod);

Loading Objects Using Reflection

This helper class loads a bunch of objects from assemblies found in the specified search path. The objects must support an interface of the given type eg usage. List<ISomeInterface> plugIns = PluginHelper.LoadPlugins <ISomeInterface>(@".\");
class PluginHelper
{

  // Loading a bunch of objects dynamically using reflection
  // In this case the type parameter specifies an interface for
  // an object with a public default constructor
  public static IList<INTERFACE> LoadPlugins<INTERFACE>(
         string searchPath)
  //where INTERFACE :  // (only reference types)
  {
    List<INTERFACE> objList = new List<INTERFACE>();

    string[] files = Directory.GetFiles(searchPath, "*.dll");
    foreach (string file in files)
    {
      try
      {
        Assembly assembly = Assembly.LoadFrom(file);
        foreach (Type type in assembly.GetTypes())
        {
          if (!type.IsClass || type.IsNotPublic) continue;
          Type[] interfaces = type.GetInterfaces();
          if (((IList<Type>)interfaces).Contains(typeof(INTERFACE)))
          {
            try
            {

              // Find the default constructor
              ConstructorInfo conInfo = type.GetConstructor(new Type[0]);
              bool hasPublicDefaultConstructor = ((conInfo != null) &&
                  ((conInfo.Attributes | MethodAttributes.Public) > 0));
              if (hasPublicDefaultConstructor)
              {
                object obj = Activator.CreateInstance(type);
                INTERFACE instance = (INTERFACE)obj;
                Debug.Assert(instance != null);
                objList.Add(instance);
              }
              else
              {
                Trace.WriteLine("LoadPlugins<INTERFACE>() - Can not create the type \'" +
                    type.ToString() + "\' in assembly \'" + file +
                    "\' as it does not have a public default constructor");
              }
            }
            catch (Exception ex)
            {
              Trace.WriteLine("Exception occurred creating an instance of \'" +
                  type.ToString() + "\' from assembly \'" + file + "\'");
            }

          }

        }
      }
      catch (Exception ex)
      {
        Trace.WriteLine("Exception occurred trying to load from assembly \'" +
            file + "\'");
      }
    }
    return objList;
  }

}

Xml Serialisation/Deserialisation

A simple helper class
using System.Xml.Serialization;

...
public static class XmlSerializationHelper
{

    // Serialize the given type (only reference types) to an Xml string
    // Catches any exceptions
    // Eg:
    // string xmlString = SerializationHelper.SerializeToXml<MyClass>(myClass);      
    public static string TrySerializeToXml<T>(this T targetObj, params Type[] extraTypes)
        where T : class // (only reference types)
    {
        string res = string.Empty;
        try
        {
            StringBuilder builder = new StringBuilder();
            XmlSerializer xmlSerializer = new XmlSerializer(typeof (T), extraTypes);
            xmlSerializer.Serialize(new StringWriter(builder), targetObj);
            res = builder.ToString();
        }
        catch (Exception ex)
        {
            Trace.WriteLine("SerializationHelper.SerializeToXml<T>: " +
                            "Exception occurred during deserialization " + ex.ToString());
            Debug.Assert(false, "Exception occurred during serialization " +
                                ex.ToString());
        }
        return res;
    }


    // Deserialize the given type (only reference types) from an Xml string
    // Eg:
    // MyClass myObj = SerializationHelper.DeserializeFromXml<MyClass>
    //(xmlString);
    public static T TryDeserializeFromXml<T>(this string xml, params Type[] extraTypes)
        where T : class // (only reference types)
    {
        T obj = null;
        try
        {
            XmlSerializer xmlSerializer = new XmlSerializer(typeof (T), extraTypes);
            obj = (T) xmlSerializer.Deserialize(new StringReader(xml));
        }
        catch (Exception ex)
        {
            Trace.WriteLine("SerializationHelper.DeserializeFromXml<T>: " +
                            "Exception occurred during deserialization " + ex.ToString());
            Debug.Assert(false, "Exception occurred during deserialization " +
                                ex.ToString());
        }
        return obj;
    }


    // Serialize the given type (only reference types) to an Xml filePath
    public static void TrySerializeToXmlFile<T>(this T targetObj, 
        string filePath, params Type[] extraTypes)
        where T : class // (only reference types)
    {
        try
        {
            using (TextWriter tw = new StreamWriter(filePath))
            {
                XmlSerializer xmlSerializer = new XmlSerializer(typeof (T), extraTypes);
                xmlSerializer.Serialize(tw, targetObj);
                tw.Close();
            }
        }
        catch (Exception ex)
        {
            Trace.WriteLine("SerializationHelper.SerializeToXml<T>: " +
                            "Exception occurred during deserialization " + ex.ToString());
            Debug.Assert(false, "Exception occurred during serialization " +
                                ex.ToString());
        }
    }


    // Deserialize the given type (only reference types) from an Xml filePath
    public static T TryDeserializeFromXmlFile<T>(FileInfo file, params Type[] extraTypes)
        where T : class // (only reference types)
    {
        T obj = null;
        try
        {
            using (Stream fs = new FileStream(file.FullName, FileMode.Open))
            {
              // Use an XmlReader as according to the MSDN documentation it
              // "automatically detects and uses the encoding specified by 
              // the XML document."
              using (XmlReader xmlReader = new XmlTextReader(fs))
              {
                 XmlSerializer serializer = new XmlSerializer(typeof (T), extraTypes);
                 obj = (T) serializer.Deserialize(xmlReader);
              }
            }  
            //using (TextReader tr = new StreamReader(file.FullName))
            //{
            //    XmlSerializer serializer = new XmlSerializer(typeof (T), extraTypes);
            //    obj = (T) serializer.Deserialize(tr);
            //    tr.Close();
            //}
        }
        catch (Exception ex)
        {
            Trace.WriteLine("SerializationHelper.TryDeserializeFromXmlFile<T>: " +
                            "Exception occurred during deserialization " + ex.ToString());
            Debug.Assert(false, "Exception occurred during deserialization " +
                                ex.ToString());
        }
        return obj;
    }


}

Using this XmlSerialiser/Deserialiser sample
class XmlSerialiserDeserialiserTester
{
  public void TestTaskSerialisation()
  {
    string testPath = Path.Combine(Path.GetTempPath(), "TestSerializer.xml");

    TaskManager tm = new TaskManager();
    tm.Add(new Task { When = Task.WhenEnum.Fortnight, Displayable = true, 
        Description = "Buy water proofing spray" });
    string serialised = tm.TrySerializeToXml<taskmanager>(); // Serialize
    Debug.WriteLine(serialised);

    TaskManager dtm = serialised.TryDeserializeFromXml<taskmanager>(); // Deserialize
    Debug.Assert(tm.Count == dtm.Count);
    Debug.Assert(tm[0].Description.Equals(dtm[0].Description, 
                                          StringComparison.InvariantCultureIgnoreCase));
  }
}

public class TaskManager : List<Task>
{
}

public class Task
{
 public enum WhenEnum
 {
  Fortnight = 1,
  Month = 2,
  Year = 3,
 }
 public WhenEnum When { get; set; }
 public bool Displayable { get; set; }
 public string Description { get; set; }
}

Symmetric Encryption in C#

The following code is based on that found in this article: Cryptography Simplified in Microsoft .NET The Key and the IV are needed to decrypt the encrypted text
using System;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using System.Diagnostics;

...

// Simple Symmetric Encryption helper class
// Encrypts/Decrypts strings
public class SymmetricEncryptor
{
    // Private Variables for this Form
    private SymmetricAlgorithm m_EncryptionAlgorithmn;

    //Default constructor. Default Encryption algorithmn 
    // to TripleDESCryptoServiceProvider
    public SymmetricEncryptor()
    {
        m_EncryptionAlgorithmn = Rijndael.Create();
    }

    public SymmetricEncryptor(SymmetricAlgorithm symmetricAlgorithm)
    {
        m_EncryptionAlgorithmn = symmetricAlgorithm;
    }

    // Generate a Key for use with the Encryptor
    public string GenerateKeyString()
    {
        m_EncryptionAlgorithmn.GenerateKey();
        return Convert.ToBase64String(m_EncryptionAlgorithmn.Key);
    }

    // Generate an Initialisation Vector (as a string) for use with the Encryptor
    public string GenerateIVString()
    {
        m_EncryptionAlgorithmn.GenerateIV();
        return Convert.ToBase64String(m_EncryptionAlgorithmn.IV);
    }

    // Generate an Initialisation Vector for use with the Encryptor
    public byte[] GenerateIV()
    {
        m_EncryptionAlgorithmn.GenerateIV();
        return m_EncryptionAlgorithmn.IV;
    }


    // Get/Set the a Key for use with the Encryptor. 
    // Note the Key is provided as a Base 64 encoded string
    public string KeyString
    {
        get
        { return Convert.ToBase64String(m_EncryptionAlgorithmn.Key); }
        set
        { m_EncryptionAlgorithmn.Key = Convert.FromBase64String(value); }
    }

    // Get/Set the a Initialisation Vector for use
    // with the Encryptor. Note the Initialisation 
    // Vector is provided as a Base 64 encoded string
    public string IVString
    {
        get
        {
            return Convert.ToBase64String(m_EncryptionAlgorithmn.IV);
        }
        set
        { m_EncryptionAlgorithmn.IV = Convert.FromBase64String(value); }
    }


    // Get/Set the a Key for use with the Encryptor. 
    // Note the Key is provided as a Base 64 encoded string
    public byte[] Key
    {
        get
        { return m_EncryptionAlgorithmn.Key; }
        set
        { m_EncryptionAlgorithmn.Key = value; }
    }

    // Get/Set the a Initialisation Vector for use with the Encryptor.
    public byte[] IV
    {
        get
        { return m_EncryptionAlgorithmn.IV; }
        set
        { m_EncryptionAlgorithmn.IV = value; }
    }

    // Encrypt a string
    public string EncryptToString(string Value)
    {
        ICryptoTransform ct = m_EncryptionAlgorithmn.CreateEncryptor(
            m_EncryptionAlgorithmn.Key,
            m_EncryptionAlgorithmn.IV);
        byte[] bytes = Encoding.UTF8.GetBytes(Value);
        bytes = ApplyCryptoTransform(bytes, ct);
        return Convert.ToBase64String(bytes);
    }

    // Decrypt a string
    public string DecryptFromString(string Value)
    {
        ICryptoTransform ct = m_EncryptionAlgorithmn.CreateDecryptor(
            m_EncryptionAlgorithmn.Key,
            m_EncryptionAlgorithmn.IV);
        byte[] bytes = Convert.FromBase64String(Value);
        bytes = ApplyCryptoTransform(bytes, ct);
        return Encoding.UTF8.GetString(bytes);
    }

    // Encrypt a string
    public byte[] EncryptToBytes(string Value)
    {
        ICryptoTransform ct = m_EncryptionAlgorithmn.CreateEncryptor(
            m_EncryptionAlgorithmn.Key,
            m_EncryptionAlgorithmn.IV);
        byte[] bytes = Encoding.UTF8.GetBytes(Value);
        bytes = ApplyCryptoTransform(bytes, ct);
        return bytes;
    }

    // Decrypt a string
    public string DecryptFromBytes(byte[] encrBytes)
    {
        ICryptoTransform ct = m_EncryptionAlgorithmn.CreateDecryptor(
            m_EncryptionAlgorithmn.Key,
            m_EncryptionAlgorithmn.IV);
        byte[] bytes = ApplyCryptoTransform(encrBytes, ct);
        return Encoding.UTF8.GetString(bytes);
    }


    private static byte[] ApplyCryptoTransform(byte[] bytes,
        ICryptoTransform ct)
    {
        MemoryStream ms = new MemoryStream();
        CryptoStream cs = new CryptoStream(ms, ct, CryptoStreamMode.Write);
        cs.Write(bytes, 0, bytes.Length);
        cs.FlushFinalBlock();
        cs.Close();

        return ms.ToArray();
    }

    public byte[] GenerateKey()
    {
        m_EncryptionAlgorithmn.GenerateKey();
        return m_EncryptionAlgorithmn.Key;
    }
}
Here is a tester that demonstrates usage of the class.
public class SymmetricEncryptorTester
{
    public void Test()
    {
        string test = "98The0quick1brown2fox3jumps4over5the6lazy7cow";
        byte[] key;
        byte[] iv;
        string encrypted;
        string res;
        {
            SymmetricEncryptor se = new SymmetricEncryptor();
            key = se.GenerateKey();
            iv = se.GenerateIV();
            Debug.WriteLine(ByteToArray("key", key));
            Debug.WriteLine(ByteToArray("iv", iv));
            encrypted = se.EncryptToString(test);
            Debug.WriteLine("encrypted=" + encrypted);
        }
        {
            SymmetricEncryptor se = new SymmetricEncryptor();
            se.IV = iv;
            se.Key = key;
            res = se.DecryptFromString(encrypted);
            Debug.Assert(res.Equals(test, StringComparison.InvariantCulture));
            Debug.WriteLine("res=" + res);
        }
    }

    public void Test2()
    {
        string test = "98The0quick1brown2fox3jumps4over5the6lazy7cow";
        byte[] key;
        byte[] iv;
        byte[] encrypted;
        string res = "";
        {
            SymmetricEncryptor se = new SymmetricEncryptor();
            key = se.GenerateKey();
            iv = se.GenerateIV();
            Debug.WriteLine(ByteToArray("key", key));
            Debug.WriteLine(ByteToArray("iv", iv));
            encrypted = se.EncryptToBytes(test);
            Debug.WriteLine(ByteToArray("encrypted", encrypted));
        }
        {
            SymmetricEncryptor se = new SymmetricEncryptor();
            se.IV = iv;
            se.Key = key;
            res = se.DecryptFromBytes(encrypted);
            Debug.Assert(res.Equals(test, StringComparison.InvariantCulture));
            Debug.WriteLine("res=" + res);
        }

    }


    private string ByteToArray(string name, byte[] bytes)
    {
        string res = "byte[] " + name + " = new byte[" 
            + bytes.Length.ToString() + "] { ";
        for (int ix = 0; ix < bytes.Length; ix++)
        {
            res += "0x" + bytes[ix].ToString("X");
            if (ix < (bytes.Length - 1))
                res += ", ";
        }
        res += " }";
        return res;
    }
}

August 5, 2008

Base 64 Encoding

byte[] key = new byte[32] { 0xEC, 0x16, 0x50, 0x73, 0xB8,
0x91, 0xCE, 0x40, 0x68, 0x58, 0xEC, 0x31, 0x4E, 0xF1, 0xD3,
0x87, 0x49, 0x27, 0x25, 0xA2, 0x3B, 0xCD, 0xA8, 0x4C, 0x39,
0x41, 0xE2, 0x37, 0x62, 0xEF, 0xE9, 0x43 }; // Encode to Base 64 string string base64Encoded = Convert.ToBase64String(key); // Convert Base 64 string back to a byte array byte[] bytes = Convert.FromBase64String(base64Encoded);

Cmd Shell

To exectue a command with the cmd.exe shell use the /k or /c argument /k => Execute the command and keep the shell window open /c => Execute and then close the Cmd window eg:
cmd.exe /k ipconfig /all

File and Directory Classes

Generally it is best to use the FileSystemInfo (abstract base), FileInfo (for files), and DirectoryInfo (for directories) classes. Here is a class diagram to show how the 3 are related:
These classes are found in the "System.IO" namespace.

The "File" and "Directory" classes are used directly on strings:
Using System.IO;
...
// Determining If A File Is A Directory
private bool IsDirectory(string path)
{
    bool res = ((File.GetAttributes(path) & FileAttributes.Directory) ==
                FileAttributes.Directory);
    return res;
}

File.Exists(filname); // To check if a file exists
Directory.Exists(path) // To check if a directory exists

//To get the last time for the last change to a file use:
File.GetLastWriteTime(fileUri).ToString();
Some Iterators for iterating over Files and/or Directories recursively
public static class FileSystemInfoExtender
{
    // Iterate all files in a path, with 
    // an option to recurse through subdirectories
    public static IEnumerable<FileSystemInfo> 
      IterateFiles(this FileSystemInfo targ, bool recurse)
    {
        if (targ == null)
            throw new ArgumentNullException("targ");

        // return initial target
        yield return targ;

        if (recurse)
        {
            DirectoryInfo diTarg = targ as DirectoryInfo;
            // If targ is a directory
            if (diTarg != null)
            {                   
                // Get its contents as FileSystemInfo objects
                FileSystemInfo[] fsis = TryGetFileSystemInfos(diTarg);
                foreach (FileSystemInfo fsi in fsis)
                {
                    foreach (FileSystemInfo fsiInner in 
                        fsi.IterateFiles(recurse))
                        yield return fsiInner;
                }
            }
        }
    }

    // Iterate all files in a path, with 
    // recurse through subdirectories first
    public static IEnumerable<FileSystemInfo> 
        IterateFilesChildrenFirst(
          this FileSystemInfo targ, 
          bool recurse)
    {
        if (targ == null)
            throw new ArgumentNullException("targ");

        if (recurse)
        {
            DirectoryInfo diTarg = targ as DirectoryInfo;
            // If targ is a directory
            if (diTarg != null)
            {
                // Get its contents as FileSystemInfo objects
                FileSystemInfo[] fsis = TryGetFileSystemInfos(diTarg);
                foreach (FileSystemInfo fsi in fsis)
                {
                    foreach (FileSystemInfo fsiInner in
                        fsi.IterateFilesChildrenFirst(recurse))
                        yield return fsiInner;
                }
            }
        }

        // return initial target
        yield return targ;
    }


    private static FileSystemInfo[] TryGetFileSystemInfos(
      DirectoryInfo diTarg)
    {
        FileSystemInfo[] fsis = new FileSystemInfo[0];
        try
        {
            fsis = diTarg.GetFileSystemInfos();
        }
        catch (Exception ex)
        { 
            LogError("Calling GetFileSystemInfos() on \'" + diTarg.FullName + "\' threw " + 
                "an exception: " + ex.ToString());
        }
        return fsis;
    }

    // Iterate all directories in a path, with
    // an option to recurse through subdirectories
    public static IEnumerable<DirectoryInfo> IterateDirectories(
        this DirectoryInfo diTarg, bool recurse)
    {
        if (diTarg == null)
            throw new ArgumentNullException("diTarg");

        if (recurse) // return its children
        {
            DirectoryInfo[] dirs = TryGetDirectories(diTarg);
            foreach (DirectoryInfo dir in dirs)
            {
                foreach (DirectoryInfo dirInner in 
                    dir.IterateDirectories(recurse))
                {
                    yield return dirInner;
                }
            }
        }
        yield return diTarg; // return the current dir
    }

    private static DirectoryInfo[] TryGetDirectories(
        DirectoryInfo diTarg)
    {
        DirectoryInfo[] dirs = new DirectoryInfo[0];
        try
        {
            dirs = diTarg.GetDirectories();
        }
        catch (Exception ex)
        {
            LogError("Calling GetDirectories() on \'" +
                diTarg.FullName + 
                "\' threw " + 
                "an exception: " + 
                ex.ToString());
        }
        return dirs;
    }
 
    private static void LogError(string exStr)
    {
        Debug.WriteLine(exStr);
    }

    public static bool TryDeleteFileSystemInfo(this FileSystemInfo fsi)
    {
        bool success = true;
        try
        {
            fsi.Delete();
        }
        catch (Exception ex)
        {
            success = false;
            LogError("Delete \'" + 
                fsi.FullName + 
                "\' threw an exception: " +
                ex.ToString());
        }
        return success;
    }
}
for something similar check out the Directory.GetFiles(string path, string searchPattern, SearchOption searchOption); method

#region FileAttributesExtender

public static class FileAttributesExtender
{
    // Return lhs flags plus rhs flags
    public static FileAttributes Union(
        this FileAttributes lhs, FileAttributes rhs)
    {
        return lhs | rhs;
    }

    // Return flags common to lhs and rhs
    public static FileAttributes Intersection(
         this FileAttributes lhs, FileAttributes rhs)
    {
        return lhs & rhs;
    }

    // Return lhs flags minus rhs flags
    public static FileAttributes Difference(
         this FileAttributes lhs, FileAttributes rhs)
    {
        FileAttributes common = lhs & rhs;
        int res = (int)lhs - (int)common;
        return (FileAttributes)(res);
    }

    // Return true if lhs contains all the flags within rhs
    public static bool Contains(
         this FileAttributes lhs, FileAttributes rhs)
    {
        FileAttributes common = lhs & rhs;
        return (common == rhs);
    }

    // Return true if lhs contains one of the flags within rhs
    public static bool ContainsAnyOf(
        this FileAttributes lhs, FileAttributes rhs)
    {
        FileAttributes common = lhs & rhs;
        return ((int)common > 0);
    }

    // NON-extension methods here
    public static FileAttributes FromString(string source)
    {
        FileAttributes res = (FileAttributes)Enum.Parse(
             typeof(FileAttributes), source, true);
        return res;
    }

}

#endregion FileAttributesExtender
Sample usage to delete user files in their 'Temp' directory
private void DeleteTemporaryFiles(string tempPath)
{
  System.IO.DirectoryInfo targ = new 
         System.IO.DirectoryInfo(tempPath);
  bool success = false;
  foreach (System.IO.FileSystemInfo fsi in 
                     targ.IterateFiles(false))
  {
    Debug.Write(fsi.FullName);
    Debug.Write(" Attributes:" + fsi.Attributes.ToString("f"));
    if (!fsi.Attributes.ContainsAnyOf(
           System.IO.FileAttributes.System | 
           System.IO.FileAttributes.Temporary))
    {
      success = true;
      try
      {
        fsi.Delete();
      }
      catch (Exception ex)
      {
        success = false;
        Debug.Write(ex.ToString());
      }
      Debug.Write(success ? " Deleted" : " Could not Delete!");
    }
    Debug.WriteLine("");
  }
}

Useful string methods

//To check a string contains a substring:
bool ContainsString(string container, string contained)
{
  return (container.IndexOf(contained) > -1);
}
// To replace all space characters
mystring.Trim().Replace(" ", string.Empty);
string.Join Opposite To string.Split
private static void TestJoinSplit()
{
    string[] test = new string[] { "x", "y", "z" };
    string joined = string.Join(",", test);
    Debug.WriteLine(joined);
    string[] splitUp = joined.Split(',');
    for (int ix = 0; ix < test.Length; ix++)
    {
        Debug.Assert(splitUp[ix] == test[ix]);
    }
}
Outputs: x,y,z

Using Shell To Start A Process

Starting another OS process. Eg to open an image in the defult editor/viewer
Process shellRunProcess = new Process();
shellRunProcess.StartInfo.FileName = fileName;
shellRunProcess.Start();

Post Build Events

Post Build Event to copy Your Plug-in DLL to the XXX Output directory Add to PostBuild for the project:
copy "$(TargetPath)" "$(ProjectDir)..\XXX\$(OutDir)"
Post Build Event for XmlSerialiser Projects Add to PostBuild for the project:
"$(DevEnvDir)..\..\SDK\v2.0\Bin\sgen.exe"  "$(TargetPath)"
copy "$(TargetDir)$(TargetName).XmlSerializers.dll" "$(ProjectDir)..\XXX\bin\Debug\"

March 6, 2008

WPF Links

AsReadyOnly method

The AsReadyOnly method. This method is exposed by the List, Set, Array<>, and others and generates what is basically an adapter to your collection. The return value is a System.Collections.ObjectModel.ReadOnlyCollection that is the best of both worlds , it shows live data from the internal collection and it doesn't let the consumer modify the collection contents. Here's an example of the implementation
public class MyManagerClass
{
     private List _objects = new List();

     public ReadOnlyCollection Objects
     {
          get { return _objects.AsReadOnly(); }
     }
}

Setting up Log4Net in the application config file.

Setting up log4net to use a rolling file appender and a trace appender
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="log4net"
 type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
  </configSections>
  <log4net debug="false">
    <appender name="RollingFileAppender"
 type="log4net.Appender.RollingFileAppender">
      <file
 value="${ENVIROMENTALVARIABLENAME}\\MyApplicationName.exe.txt" />
      <appendToFile value="true" />
      <maximumFileSize value="100KB" />
      <maxSizeRollBackups value="5" />
      <param name="RollingStyle" value="Size" />
      <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] -
 %m%n" />
      </layout>
    </appender>
    <appender name="TraceAppender"
 type="log4net.Appender.TraceAppender">
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%d [%t] %-5p %c [%x] - %m%n" />
      </layout>
    </appender>
    <root>
      <priority value="ALL" />
      <appender-ref ref="RollingFileAppender" />
      <appender-ref ref="TraceAppender" />
    </root>
  </log4net>
</configuration>

Reading The Number Of Rows In A Table Search

const string NUM_XXX = 
"SELECT COUNT(*) AS numXXXs"
"FROM ... 
"WHERE ...

using (databaseConnection = new SqlConnection(XXXConnectionString))
{
    databaseConnection.Open();
    using (SqlCommand command = new SqlCommand())
    {
        command.Connection = databaseConnection;
        command.CommandText = NUM_XXX;
        command.Parameters.AddWithValue("@Id", id);

        SqlDataReader reader = command.ExecuteReader();
        if (reader != null)
        {
            if (reader.HasRows && reader.Read())
            {
                numXXXs = reader.GetInt32(0);
            }
            reader.Close();
        }

    }
}

Simple Background Worker Object Template

BackgroundWorker backgroundWorker
Worker worker;

private void AsyncStartWork()
{
    if (!backgroundWorker.IsBusy)
    {
        worker = new Worker(...);
        backgroundWorker.DoWork += new
 DoWorkEventHandler(backgroundWorker_DoWork);
        backgroundWorker.RunWorkerCompleted += new
 RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
        backgroundWorker.RunWorkerAsync((object)worker);
    }
}

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    Worker worker = e.Argument as Worker;
    if (worker != null)
    {
        worker.DoSomething();
    }
}

private void backgroundWorker_RunWorkerCompleted(object sender,
 RunWorkerCompletedEventArgs e)
{
    backgroundWorker.DoWork -= new
 DoWorkEventHandler(backgroundWorker_DoWork);
    backgroundWorker.RunWorkerCompleted -= new
 RunWorkerCompletedEventHandler(
        backgroundWorker_RunWorkerCompleted);

    // Update GUI

    // IF necessary do something with results
    Show(worker.Results);
}

Links To Developer Tools

Web Developer Add In for FireFox
Yet another VB to C# Converter
Ultimate Developers And Power Tool Users List
Console A Command Prompt Replacement

February 2, 2008

Converting A Class Heirarchy To Xml And Then Html

public class XXXToHtmlHelper
{
    private string xml;
    private Encoding encodingStandard;

    public XXXToHtmlHelper()
    {
        string tmpFileName = Path.GetTempFileName();
        if (Path.HasExtension(tmpFileName))
        {
            tmpFileName = Path.GetFileNameWithoutExtension(Path.GetTempFileName());
        }
        xml = Path.Combine(Path.GetTempPath(), tmpFileName + ".xml");
    }

    public void GenerateHtml(
        Encoding encoding, 
        string xsl, 
        XXX xxx,
        string html)
    {
        XXXToXmlFile(xml, encoding, xxx);
        XXX_XmlToHtml(xml, xsl, html);
        if (File.Exists(xml))
        {
            File.Delete(xml);
        }
    }

    private static void XXXToXmlFile(
        string xmlFile,
        Encoding encoding,
        XXX xxxObj)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            XmlTextWriter writer = new XmlTextWriter(ms, encoding);
            try
            {
                writer.Formatting = Formatting.Indented;
                writer.WriteStartDocument();
                xxxObj.ToXml(writer);
                writer.WriteEndDocument();
                writer.Flush();
            }
            finally
            {
                writer.Close();
            }
            File.WriteAllBytes(xml, ms.ToArray());
        }
    }


    private void XXX_XmlToHtml(string xmlInput, string htmlOutput)
    {
        XsltArgumentList args = new XsltArgumentList();
        args.AddParam("DATE", "", DateTime.Now.ToString("F"));
        args.AddParam("COMMENT", "", "Some comment");
        args.AddParam("USER", "", Environment.UserName);
        XslCompiledTransform xslt = new XslCompiledTransform();
        xslt.Load(xslFile);
        MemoryStream ms = new MemoryStream();
        xslt.Transform(xmlInput, args, ms);
        File.WriteAllBytes(htmlOutput, ms.ToArray());
    }

}

Using Wait Cursor

Cursor = Cursors.WaitCursor;
try
{

}
finally
{
    Cursor = Cursors.Default;
}

Keyboard Handling in Win Forms

C# Key Processing Techniques Use Form.KeyPreview = true Tells form to receive all KeyPress, KeyDown, and KeyUp events. After the form's event handlers have completed processing the keystroke, the keystroke is then assigned to the control with focus. For example, if the KeyPreview property is set to true and the currently selected control is a TextBox, after the keystroke is handled by the event-handling methods of the form the TextBox control will receive the key that was pressed. To handle keyboard events only at the form level and not allow controls to receive keyboard events, set the KeyPressEventArgs.Handled property in your form's KeyPress event-handling method to true. eg.: Hide the form when the Escape key is Pressed
myForm.KeyPreview = true;
...
protected override bool ProcessDialogKey(Keys keyData)
{
    if (keyData == Keys.Escape)
    {
        this.Hide();
        return true;
    }
    return base.ProcessDialogKey(keyData);
}

IEnumerable, ICollection, IList Compared

IEnumerable<> => Allows use of 'foreach' on a collection
ICollection<> => As IEnumerable<> + Add(), Remove(), Count, Clear(), Contains(), IsReadOnly, CopyTo()
IList<> => As ICollection<> + this[int], Insert(), IndexOf(), RemoveAt(). ie. It adds indexing type list operators
    • Can use 'return yield ???' in conjunction with IEnumerable<> to only return 1 object at a time. This is where the real power of IEnumerable comes from (not from simply returning a list or an array).
    • When returning a list decide what can be exposed to the user and return the appropriate type. 
    • Maybe its best to return an ICollection<> or IList<> and if the code client only needs to enumerate the list they can cast it to an IEnumerable<>. ie. Given ICollection<Widgets> SomeMethod() … The user could invoke it as IEnumerable<Widgets> widgets = SomeMethod()

    SQL Links

    SQL Syntax - Also Shows the syntax for creating SQL tables. Not too VERBOSe but quite complete Another SQL Lookup Another SQL Lookup Another SQL Lookup Teach Yourself SQL Server SQL Server Data Types and Their .NET Framework Equivalents

    Anonymous Delegates And Iterators

    c# 2.0 Iterators
    Using anonymous delegates

    This code: (Note how an anonymous method can access local variables!)
    ...
    XXX mainXXX = ...
    ...
    xxxList.RemoveAll(
        delegate(XXX xxx)
        {
            return xxx.Id == mainXXX.Id; 
        }
    );
    
    Does the same as this:
    List entriesToRemove = new List();
    foreach (XXX xxx in xxxList)
    {
        if (xxx.Id == mainXXX.Id)
        {
            entriesToRemove.Add(xxx);
        }
    }
    foreach (XXX xxx in entriesToRemove)
    {
        xxxList.Remove(userToRemove);
    }
    

    Calculate Drive Free Space

    Calculate the Ammount of Freespace on a Given Drive
    private static long FreeSpaceOnDrive(string path)
    {
        long res = 0;
        string root = string.Empty;
        if (Path.IsPathRooted(path))
        {
            root = Path.GetPathRoot(path);
            DriveInfo[] drives = System.IO.DriveInfo.GetDrives();
            foreach (DriveInfo drive in drives)
            {
                if (root.Equals(Path.GetPathRoot(drive.Name), 
                    StringComparison.InvariantCultureIgnoreCase))
                {
                    if (drive.IsReady)
                    {
                        res = drive.AvailableFreeSpace;
                        break;
                    }
                }
            }
        }
        return res;
    }