November 25, 2007

Using HelpRequested

The following will get help related to the control which has the mouse over it by pressing the F1 button

this.HelpRequested += new HelpEventHandler(this.XXXDialog_HelpHandler);
...
private void XXXDialog_HelpHandler(
  object sender, HelpEventArgs helpEvent)
{
  if (helpEventHandler != null)
  {
    Point pt = this.PointToControl(e.MousePos);
    Control control = this.GetChildAtPoint(pt);
    
    GetHelpOn(control);

    helpEvent.Handled = true;
  }
}

c# Printing

See this link C# Printing

CultureInfo, DateSeparator and TimeSeparator

CultureInfo ci = new CultureInfo("de-DE");
string dateSep = CultureInfo.CurrentCulture.DateTimeFormat.DateSeparator;
string timeSep = CultureInfo.CurrentCulture.DateTimeFormat.TimeSeparator;

Using the Params keyword

string[] ReplaceInStrings(char oldchar, char newchar, params string[] src)
{
    string[] res = new string[src.Length];
    int ix = 0;
    foreach (string targ in src)
    {
        res[ix++] = targ.Replace(oldchar, newchar);
    }
    return res;
}
The nice thing about the use of the 'params' keyword is that it can take an array parameter directly or a series of the specified type. It can even work with no parameters of the specified type. The following code demonstrates this behaviour
private void ParamsTest()
{
    string[] res;
    string[] strings = new string[] { "Some_string", "Another_string"};
    // Pass an array directly
    res = ReplaceInStrings('_', ' ', strings); 
    // Pass a series of objects of the specified type, this is automatically
    // converted to an array
    res = ReplaceInStrings('_', ' ', "This_string", "That_string", "Unchanged"); 
    // Pass a single object of the specified type
    res = ReplaceInStrings('_', ' ', "A_Single_string"); 
    // Pass NO objects of the specified type!
    // This still works an empty array is passed into the routine
    res = ReplaceInStrings('_', ' '); 

}
can it be used on a remoting interface?

Flags Based Enumerated Types

An extension class that extends a flag based enumerated type with set/group theory type operations. See FileAttributesExtender for a usage of this class.
public partial class EnumFlagsForm : Form
{
    [Flags]
    public enum EnumFlags
    {
        None = 0,
        Emergency_Stop = 0x1,
        Greasey = 0x2,
        Spot_Spot = 0x4,
        Doughnuts = 0x8,
        Lift_Moving = 0x10,
        Doors_Open = 0x20,
        Forbidden = 0x40
    }

//SourceTypes sourceTypes;
public static class EnumFlagsExtender
{
 // Return lhs flags plus rhs flags
 public static EnumFlags Union(this EnumFlags lhs, EnumFlags rhs)
 {
  return lhs | rhs;
 }

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

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

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

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

 
 // NON-extension methods here

 public static EnumFlags FromString(string source)
 {
  EnumFlags res = (EnumFlags)Enum.Parse(typeof(EnumFlags), source, true);
  return res;
 }

    }

    public void Test1()
    {
      EnumFlags test = EnumFlags.Lift_Moving |
          EnumFlags.Doors_Open | EnumFlags.Doughnuts;
      string str = test.ToString();
      //str = str.Replace('_', ' ');
      Debug.WriteLine(str);
      EnumFlags newtest = EnumFlagsExtender.FromString(str);
      Debug.Assert(newtest == test);      
    }

public void EnumFlagsSubtractTest()
{
    EnumFlags test1 = EnumFlags.Lift_Moving | EnumFlags.Doors_Open |
        EnumFlags.Doughnuts | EnumFlags.Emergency_Stop;
    EnumFlags test2 = EnumFlags.Lift_Moving | EnumFlags.Forbidden |
        EnumFlags.Emergency_Stop;
    EnumFlags expected = EnumFlags.Doors_Open | EnumFlags.Doughnuts;
    EnumFlags outcome = test1.Subtract(test2);
    Debug.Assert(outcome == expected);

    expected = EnumFlags.Doors_Open | EnumFlags.Doughnuts | EnumFlags.Greasey;
    outcome = outcome.Union(EnumFlags.Greasey);
    Debug.Assert(outcome == expected);

    EnumFlags test3 = EnumFlags.Doughnuts | EnumFlags.Greasey;
    bool res = outcome.Contains(test3);
    Debug.Assert(res);
    
    res = outcome.Contains(EnumFlags.Lift_Moving | EnumFlags.Forbidden);
    Debug.Assert(!res);
}


    public EnumFlagsForm()
    {
        InitializeComponent();
        lbSourceTypes.Items.AddRange(
UnderscoresToSpaces(
Enum.GetNames(typeof(EnumFlags))));
        OnSelectedValueChanged(this, null);
    }

    string[] UnderscoresToSpaces(string[] src)
    {
        return ReplaceInStrings('_', ' ', src);
    }

    string[] SpacesToUnderscores(string[] src)
    {
        return ReplaceInStrings('_', ' ', src);
    }

    string SpacesToUnderscores(string src)
    {
        return src.Replace(' ', '_');
    }

    string[] ReplaceInStrings(char oldchar, char newchar, params string[] src)
    {
        string[] res = new string[src.Length];
        int ix = 0;
        foreach (string targ in src)
        {
            res[ix++] = targ.Replace(oldchar, newchar);
        }
        return res;
    }


    private void OnSelectedValueChanged(object sender, EventArgs e)
    {
        EnumFlags test = EnumFlags.None;
        foreach (string type in lbSourceTypes.SelectedItems)
        {
            test = EnumFlagsHelper.Add(test, 
EnumFlagsHelper.FromString(SpacesToUnderscores(type)));
        }
        tbSelected.Text = test.ToString();
        lblIsAudioAndVideo.Text = "WoopsTest() == " + 
(EnumFlagsHelper.WoopsTest(test)).ToString();
    }

    private void butTest_Click(object sender, EventArgs e)
    {
        Test1();
 
        EnumFlagsSubtractTest();
    }

}
Here is a visual studio code snippet for the enum extender
<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
     <CodeSnippet Format="1.0.0">
          <Header><Title>Flags Enum Extender pattern</Title>
               <Description>Implement an extender for a 'Flags' type Enum. The extender adds set type methods to the enumertaion type</Description>
               <Keywords>
                   <Keyword>Enum</Keyword>
              </Keywords>
              <Author>Roger Bovill</Author>
         </Header>
         <Snippet>
         <Declarations> 
              <Literal Editable="true">
          <ID>EnumName</ID>
          <ToolTip>Name of the '[Flags]' based enumerated type</ToolTip>
    <Default>MyEnumType</Default>  
                <Function></Function>
             </Literal>
        </Declarations>
        <Code Language="CSharp">
            <![CDATA[

#region $EnumName$Extender

    public static class $EnumName$Extender
    {
        // Return lhs flags plus rhs flags
        public static $EnumName$ Union(this $EnumName$ lhs, $EnumName$ rhs)
        {
            return lhs | rhs;
        }

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

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

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

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

        // NON-extension methods here

        public static $EnumName$ FromString(string source)
        {
            $EnumName$ res = ($EnumName$)Enum.Parse(typeof($EnumName$), source, true);
            return res;
        }

    }

#endregion $EnumName$Extender

            ]]>
        </Code>
       </Snippet>
    </CodeSnippet>
</CodeSnippets>

November 13, 2007

Web Colors

Web Colors

DateTime

Here are some links regarding DateTime string formatting and parsing: Truncating Milliseconds
private static DateTime TruncateMilliSeconds(DateTime dt)
{
  DateTime trunc = new DateTime(dt.Ticks - (10000*dt.Millisecond));
  Debug.Assert(trunc.Millisecond == 0);
  return trunc;
}
Parsing a date from a non standard form
DateTime.TryParseExact(dateStart, "yyyyMMdd",
  System.Globalization.CultureInfo.CurrentCulture,
  System.Globalization.DateTimeStyles.AssumeLocal, out m_StartDate);
Here is another example that will parse this string "Sun, 30 Jun 2013 14:14:01 +0100"
DateTime when = DateTime.MinValue;
string form = @"ddd, dd MMM yyyy HH':'mm':'ss K";
DateTime.TryParseExact(this.rawDateTime, form, 
  System.Globalization.CultureInfo.CurrentCulture,
  System.Globalization.DateTimeStyles.AssumeLocal, 
  out when);
Converting a date to a non standard string form
string datTimeStr = DateTime.UtcNow.ToString("yyyyMMdd"); 
where
M=month digit, y=year digit, d=day digit
h=hour digit (but H=24 hour digit), m=minute digit, s=second digit

Here is an example of this from renaming photos extracted from a digital camera
public class PhotoBackupOptions
{
    private string m_fileDateFormatStr = "yyyy_MMdd_HHmm";
    private string m_filenamePrefix = "Photo_";

    public string FileNameDateFormatStr
    {
        get { return m_fileDateFormatStr; }
    }

    public string FileNamePrefix
    {
        get { return m_filenamePrefix; }
    }

    public string GetPhotoFileName(FileInfo fsi)
    {
        Debug.Assert((fsi != null) && fsi.Exists);
        string res = fsi.Name;
        if (FileNameDateFormatStr.Length > 0)
        {
            DateTime dt = fsi.CreationTime;
            res = FileNamePrefix + 
                  dt.ToString(FileNameDateFormatStr) +
                  fsi.Extension;
        }
        return res;
    }
}
Here is a static method to load a date from a photo's metadata using WPF
// Retrieve the datetime from an image WITHOUT loading the whole thing
public static bool GetDateTakenFromImage(FileInfo fi, out DateTime dateTaken)
{
    dateTaken = DateTime.MinValue;
    bool found = false;
    try
    {
        using (FileStream fs = new FileStream(fi.FullName, 
            FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            BitmapMetadata md = (BitmapMetadata)BitmapFrame.Create(fs).Metadata;              
            found = DateTime.TryParse(md.DateTaken, out dateTaken);
        }
    }
    catch (Exception)
    {
        Trace.WriteLine("Could not get DateTaken from the image: \'" + fi.FullName + "\'");
    }
    return found;
}

C# SQL Update Key Value Type Table

// Updates a table called databaseTableName with columns 
// 'Key' and 'Value'. Its untested!
public void UpdateSettingValueEntry(
  string databaseTableName, string key, string value)
{
  private const string updateCommand = 
   "UPDATE {0} SET Value = @value WHERE Key = '{1}'"
  using (SqlConnection databaseConnection = 
         new SqlConnection(DatabaseConnectionString))
  {
    try
    {
      databaseConnection.Open();

      using (SqlCommand command = new SqlCommand())
      {
        command.Connection = databaseConnection;
        command.CommandText = string.format(updateCommand, 
              databaseTableName, key);
        command.Parameters.AddWithValue("@value", value);
        Debug.Trace("SQL({0})", command.CommandText);
        int rows = command.ExecuteNonQuery();
        if (rows == 1)
        {
           Debug.WriteLine("Updated key \'" + key + 
              "\' to value of \'" +
               value + "\'");
        }
        else
        {
          HandleError("Updated key \'" + key + 
           "\' to value of \'" + value + 
           "\' returned unexpected row count of \'" +
           rows + "\'");
        }
        if (rows < 1)
        {
          HandleUpdateError(xxx);
        }
      }
    }
    catch (SqlException se)
    {
      HandleException(se);
    }
  }
}

C# SQL Update, Insert, Read, Delete

public void UpdateXXXs(XXX[] xxxs)
{
    using (SqlConnection databaseConnection = 
       new SqlConnection(DatabaseConnectionString))
    {
        try
        {
            databaseConnection.Open();
            SqlTransaction trans = 
              databaseConnection.BeginTransaction();

            // One strategy is to delete the whole table 
            // and then recreate with the new rows
            // it depends on how big the table is. This is 
            // not practical with a very large table
            DeleteXXXTable(databaseConnection, trans);
            foreach (XXX xxx in xxxs)
            {
                InsertXXX(databaseConnection, trans, xxx);
            }
            trans.Commit();
        }
        catch (SqlException se)
        {
            trans.Rollback();
            HandleException(se);
        }
    }
}


private void InsertXXX(SqlConnection databaseConnection,
    SqlTransaction trans, XXX xxx)
{
    try
    {
      using (SqlCommand sqlCommand = databaseConnection.CreateCommand())
      {
        command.Connection = databaseConnection;
        command.Transaction = trans;
        command.CommandText = "INSERT INTO [XXXTable] " + 
            "([field1], [field2]) VALUES " + 
            "(@field1, @field2)";
        command.Parameters.AddWithValue("@field1", xxx.field1);
        command.Parameters.AddWithValue("@field2", xxx.field2);
        Debug.Trace("SQL({0})", command.CommandText);
        int rows = command.ExecuteNonQuery();
        if (rows < 1)
        {
            trans.Rollback();
            HandleInsertError(xxx);
        }
      }
    }
    catch (SqlException se)
    {
        trans.Rollback();
        HandleException(se);
    }
}

public XXX[] ReadSomeDatabaseTable()
{
  List xxxList = new List();

  using (SqlConnection databaseConnection = 
    new SqlConnection(SomeConnectionString))
  {
    try
    {
      databaseConnection.Open();

      using (SqlCommand command = new SqlCommand())
      {
        command.Connection = databaseConnection;
        command.CommandText = "SELECT * FROM [XXXTable] ";

        using (SqlDataReader reader = command.ExecuteReader())
        {
          if (reader != null)
          {
            while (reader.HasRows && reader.Read())
            {
              string field1 = reader.GetString(0).Trim();
              string field2 = reader.GetString(1).Trim();
              XXX xxx = new XXX(field1, field2);
              xxxList.Add(xxx);
            }
          }
        }
      }
    }
    catch (SqlException se)
    {
        HandleException(se);
    }
  }
  return xxxList.ToArray();
}

private void DeleteXXXTable(SqlConnection databaseConnection,
    SqlTransaction trans)
{
    try
    {
      using (SqlCommand command = databaseConnection.CreateCommand())
      {
        command.Connection = databaseConnection;
        command.Transaction = trans;
        command.CommandText = "DELETE FROM [XXXTable];";
        command.ExecuteNonQuery();
      }  
    }
    catch (SqlException se)
    {
        trans.Rollback();
        HandleException(se);
    }
}

November 4, 2007

Using KeyDown Event On A Grid/List Control

This code adds keyboard handling to a grid or list control. The Delete Key performs a Delete, the Insert Key performs an Insert, the Return Key performs a an edit when a single row is selected

private void xxxxxxxxxxxxx_KeyDown(object sender, KeyEventArgs e)
{
   switch (e.KeyCode)
   {
       // Delete with one or more rows selected 
       // performs a Remove on those rows
       case Keys.Delete: 
         e.Handled = true;
         DeleteSelectedRows();
           break;
       case Keys.Insert: // Insert performs an Add
         e.Handled = true;
         AddRow();
           break;
       // RETURN When a single row is selected 
       // perform an Edit, editing the currently 
       // selected row
       case Keys.Return: 
           
         e.Handled = true;
         EditSelectedRow());
           break;
       default:
           break;
   }
}