navigation
 Wednesday, March 29, 2006

Given an array of bytes containing the file data, a MIME type, and a file name:

public void DownloadBytes( byte[] bytes, string mimeType, string fileName )
{
  Response.ContentType = mimeType;
  Response.AppendHeader( "Content-Disposition", "attachment;filename=" + fileName );
  Response.BinaryWrite( bytes );
  Response.Flush();
  Response.End();
}

posted on March 29, 2006  #    by Adam Anderson  Comments [0] Trackback
 Thursday, March 23, 2006

The .NET Framework offers two methods for rounding: Decimal.Round() and Math.Round(). However, both methods implement a type of rounding known as "banker's rounding," which rounds .5 to the nearest even number. This is a different implementation from the "standard" arithmetic rounding most people are familiar with, where .5 rounds "up." Even the definition of "up" can vary, depending on whether the rounding is symmetric or asymmetric. Symmetric rounding rounds in the same direction relative to 0 (either towards or away). Asymmetric rounding always rounds in the same absolute direction (towards positive infinity or negative infinity).

Banker's rounding has its benefits, but it can cause incompatibility with other systems that implement different rounding schemes. For example, Math.Round( 8.5m ) will round to 8 in .NET, but round( 8.5, 2 ) will round to 9 in T-SQL. Inside is source code that implements arithmetic symmetric rounding in .NET, the type of rounding that T-SQL uses.

See How To Implement Custom Rounding Procedures for additional information

/// <summary>
/// Implements alternate rounding methods, in contrast to Decimal.Round()
/// and Math.Round(), which implement banker's rounding (5 rounds to even).
/// See http://support.microsoft.com/?kbid=196652 for other methods.
/// </summary>
public static class Round
{
  #region Methods

  #region ArithSym
  /// <summary>
  /// Rounds using arithmetic (5 rounds up) symmetrical (up is away from zero) rounding
  /// </summary>
  /// <param name="d">A Decimal number to be rounded.</param>
  /// <param name="decimals">The number of significant fractional digits (precision) in the return value.</param>
  /// <returns>The number nearest d with precision equal to decimals. If d is halfway between two numbers, then the nearest whole number away from zero is returned.</returns>
  public static decimal ArithSym( decimal d, int decimals )
  {
    decimal factor = Convert.ToDecimal( Math.Pow( 10, decimals ) );
    int sign = Math.Sign( d );
    return Decimal.Truncate( d * factor + 0.5m * sign ) / factor;
  }
  #endregion ArithSym

  #endregion Methods
}

posted on March 23, 2006  #    by Adam Anderson  Comments [0] Trackback
 Friday, March 17, 2006

I'm still playing around with that MakeRegion macro that Philip first posted. Today I added a regular expression to parse the first line of code and extract only the member name instead of the entire line.

For instructions on how to install, see The Blog That Started It All.

Imports EnvDTE
Imports EnvDTE80
Imports System.Diagnostics
Imports System.Text.RegularExpressions

Public Module Regions

  Sub MakeRegion()
    Regions.MakeRegion()
  End Sub

  Public Class Regions
    ' MakeRegion inserts #region and #endregion tags
    ' around selected text in the VS editor.
    Shared Sub MakeRegion()
      Dim rName As String = ""
      Dim pad As String = ""
      Dim junk As String
      Dim count, i As Integer
      Dim startpoint, endpoint, tmppoint As EditPoint

      With DTE.ActiveDocument.Selection
        startpoint = .TopPoint.CreateEditPoint()
        endpoint = .BottomPoint.CreateEditPoint
      End With

      If startpoint.EqualTo(endpoint) Then
        Exit Sub
      End If

      'ELR: ADDED THIS, to move the startpoint to the start of the line()
      'so that the Pad function works correctly
      If Not startpoint.AtStartOfLine Then
        startpoint.StartOfLine()
      End If

      Dim DefaultResponse = GetDesc(DTE.ActiveDocument.Selection.TopPoint.CreateEditPoint())
      Dim re As Regex = New Regex("\s(\w+)\s*(?:\(|\:|$)")
      DefaultResponse = re.Match(DefaultResponse).Groups(1).Value

      'IV 2004-12-13: rName = InputBox("Region Name:")
      rName = InputBox("Type the name you want to give to the region, which will appear in the Visual Studio Code Editor.", "Make Region", _
      DefaultResponse)

      rName = rName.Trim()

      If rName.Length = 0 Then
        Exit Sub
      End If

      DTE.UndoContext.Open("Insert A Region")
      Try
        junk = startpoint.GetText(startpoint.LineLength)

        pad = String.Empty
        For count = 0 To junk.Length - 1
          If junk.Substring(count, 1).Equals(" ") _
          Or junk.Substring(count, 1).Equals(vbTab) Then
            pad += junk.Substring(count, 1)
          Else
            Exit For
          End If
        Next

        'ELR: ADDED Test for Languages
        If DTE.ActiveDocument.Language = "CSharp" Then
          ' C Sharp Code
          startpoint.Insert(String.Format("{0}#region {1}{2}", _
           pad, rName, vbCrLf))
          If endpoint.LineLength = 0 Then
            endpoint.Insert(String.Format("{0}#endregion {1}{2}", _
             pad, rName, vbCrLf))
          Else
            endpoint.Insert(String.Format("{0}#endregion {1}", _
             vbCrLf & pad, rName))
          End If
        Else
          ' VB Code
          startpoint.Insert(String.Format("{0}#Region {1}{2}", _
           pad, rName, vbCrLf))
          If endpoint.LineLength = 0 Then
            endpoint.Insert(String.Format("{0}#End Region '{1}{2}", _
             pad, rName, vbCrLf))
          Else
            endpoint.Insert(String.Format("{0}#End Region '{1}{2}", _
             vbCrLf & pad, rName, vbCrLf))
          End If
        End If
      Finally
        DTE.UndoContext.Close()
      End Try
    End Sub

    ' IV: Get the description from the 1st line of code in the region
    ' i.e. ignore c# comment tags (///) or take 1st line of the comments (//)
    ' Requires adjustments for VB and other langs
    Private Shared Function GetDesc(ByVal startpoint As EditPoint) As String
      Dim line As String = ""
      Dim tmppoint As EditPoint

      line = startpoint.GetText(startpoint.LineLength)
      If (line.Length > 0) Then
        line = line.TrimStart(" ", vbTab)
        If DTE.ActiveDocument.Language = "CSharp" Then
          If (line.StartsWith("///")) Or (line.StartsWith("[")) Then
            tmppoint = startpoint
            tmppoint.LineDown()
            line = GetDesc(tmppoint)
          ElseIf (line.StartsWith("//")) Then
            line = line.TrimStart("//", " ")
          End If
          line = line.Replace("{", String.Empty)
        End If
        line = line.TrimEnd(" ", vbTab)
      End If
      Return line
    End Function
  End Class

End Module

posted on March 17, 2006  #    by Adam Anderson  Comments [0] Trackback
 Thursday, March 16, 2006

Here's a little code snippet that will search a collection of Controls for the first control of a specified type.

private object FindControlByType( Control root, Type t )
{
  if ( root != null && root.GetType().Equals( t ) )
    return root;
  foreach( Control c in root.Controls )
  {
    object node = FindControlByType( c, t );
    if ( node != null && node.GetType().Equals( t ) )
      return node;
  }
  return null;
}

Example: the following example returns the first instance of an HtmlForm in a Page's Control collection:

HtmlForm form = (HtmlForm) FindControlByType( Page, typeof( HtmlForm ) );
posted on March 16, 2006  #    by Adam Anderson  Comments [0] Trackback

Here's a mysterious bit of code that doesn't look like it ought to work, but yet it does

select top 1 *
from table
order by newid()

posted on March 16, 2006  #    by Adam Anderson  Comments [1] Trackback
 Tuesday, March 14, 2006

Sometimes you need to comment out blocks of code, but you don't necessarily want to comment out each entire line. As I was performing this very chore today, I thought to myself, "Hey, wouldn't it be nice if there was a keyboard shortcut I could use to comment a selected block of text using comment delimiters?" Then I thought to myself, "I already know how to create macros thanks to Philip's great blogs on macros. Why don't I try writing my own?" So I did. Source code within.

See Philip's great blogs for instructions on how to install macros.

Imports System
Imports EnvDTE
Imports EnvDTE80
Imports System.Diagnostics

Public Module SolutionExplorer

  Sub CollapseNodes()
    ' Get the the Solution Explorer tree
    Dim UIHSolutionExplorer As UIHierarchy
    UIHSolutionExplorer = DTE.Windows.Item( _
     Constants.vsext_wk_SProjectWindow).Object()

    ' Check if there is any open solution
    If (UIHSolutionExplorer.UIHierarchyItems.Count = 0) Then
      Return
    End If

    ' Get the top node (the name of the solution)
    Dim UIHSolutionRootNode As UIHierarchyItem
    UIHSolutionRootNode = UIHSolutionExplorer.UIHierarchyItems.Item(1)

    ' Collapse each project node
    Dim UIHItem As UIHierarchyItem
    For Each UIHItem In UIHSolutionRootNode.UIHierarchyItems
      UIHItem.UIHierarchyItems.Expanded = False
    Next

    ' Select the solution node, or else when you click
    ' on the solution windows scrollbar, it will synchronize the open document
    ' with the tree and pop out the corresponding node which is probably not
    ' what you want.
    UIHSolutionRootNode.Select(vsUISelectionType.vsUISelectionTypeSelect)
  End Sub

  Sub ExpandNodes()
    ' Get the the Solution Explorer tree
    Dim UIHSolutionExplorer As UIHierarchy
    UIHSolutionExplorer = DTE.Windows.Item( _
     Constants.vsext_wk_SProjectWindow).Object()

    ' Check if there is any open solution
    If (UIHSolutionExplorer.UIHierarchyItems.Count = 0) Then
      Return
    End If

    ' Get the top node (the name of the solution)
    Dim UIHSolutionRootNode As UIHierarchyItem
    UIHSolutionRootNode = UIHSolutionExplorer.UIHierarchyItems.Item(1)

    ' Collapse each project node
    Dim UIHItem As UIHierarchyItem
    For Each UIHItem In UIHSolutionRootNode.UIHierarchyItems
      UIHItem.UIHierarchyItems.Expanded = True
    Next

    ' Select the solution node, or else when you click
    ' on the solution windows scrollbar, it will synchronize the open document
    ' with the tree and pop out the corresponding node which is probably not
    ' what you want.
    UIHSolutionRootNode.Select(vsUISelectionType.vsUISelectionTypeSelect)
  End Sub

End Module

posted on March 14, 2006  #    by Adam Anderson  Comments [0] Trackback
 Thursday, February 23, 2006

My colleague John recently blogged about the unexpected results of using the T-SQL IN operator on a set that contains NULL. Here is another solution to the problem.There are three main ways to test for existence in another table, listed here in order of increasing performance

  1. LEFT JOIN and look for NULLs in the right table
  2. Use the IN operator
  3. Use the EXISTS operator

In general, the EXISTS operator will generate the most efficient query plan, and it also isn't subject to the very NULL pitfall that plagues the IN operator. The query that John posted:

SELECT COUNT(*)
FROM TableTarget
WHERE PrimaryKeyField NOT IN (
  SELECT ForeignKeyField
  FROM TableSource
  WHERE ForeignKeyField IS NOT NULL
)

Could be writtten like this:

SELECT COUNT(*)
FROM TableTarget t
WHERE NOT EXISTS (
  SELECT *
  FROM TableSource
  WHERE ForeignKeyField = t.PrimaryKeyField
)

posted on February 23, 2006  #    by Adam Anderson  Comments [0] Trackback
 Wednesday, February 22, 2006

Danc of Lost Garden has written many interesting and thought-provoking articles, mostly about game design. Today's article, however, is wider in scope, addressing the evolution of product design, and is well worth the read.

posted on February 22, 2006  #    by Adam Anderson  Comments [0] Trackback
 Saturday, February 18, 2006

Krugle is a search engine for source code that is supposed to make life easier for us developers. You can sign up for the Beta on their website and try it out sometime next month.  http://www.krugle.com/

posted on February 18, 2006  #    by Mike Dugan  Comments [0] Trackback