Update a DataTable that is bound to a DataGridView in C#


DataTable

The example Build a DataTable and bind it to a DataGridView in C# shows how you can bind a DataTable to a DataGridView to display data. This example shows how you can add new data to the display.

When the user clicks the Add button, the example program executes the following code.

private void btnAdd_Click(object sender, EventArgs e)
{
    NewItemDialog dlg = new NewItemDialog();
    if (dlg.ShowDialog() == DialogResult.OK)
    {
        // Make the DataTable object.
        DataTable dt = (DataTable)dgvPeople.DataSource;
        dt.Rows.Add(
            dlg.txtFirstName.Text,
            dlg.txtLastName.Text,
            dlg.txtOccupation.Text,
            int.Parse(dlg.txtSalary.Text));
    }
}

This code displays a dialog where you can enter a new name, occupation, and salary. If you click Ok, the program gets the DatagridView control’s DataSource. The form’s Load event handler set that object equal to a DataTable. (See the previous example for details.)

The program converts the DataSource into a DataTable. It then adds the data that you entered on the dialog as a new row in the DataTable. The DataGridView automatically updates its display to show the new data.

This example shows how you can add a row to the DataTable, but you should be able to manipulate it in other ways, too. For example, you should be able to remove rows from the DataTable and the DataGridView should show the result.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in controls, database | Tagged , , , , , , , , , , , | Leave a comment

Print a ListView with large contents in C#


[ListView]

The example Print the contents of a ListView control in C# explains how to print the data in a ListView control when its View property is set to Details. One difficulty when printing this kind of data is that a screen may be able to hold much more data than a printed page so it’s hard to fit everything in. The previous example handles that problems by assuming all of the data can fit in the available area. In particular it assumes that every data item can fit within a single row inside its column’s current width.

This example uses a different approach. It makes each piece of data fit within its column’s width but allows data items to span multiple lines if necessary.

The basic approach for each row is to draw a row’s items in their allowed column widths and measure the amount of vertical space each needs. After drawing all of the items, the program draws boxes around them that are as tall as the item that needed the most vertical space. The code then starts drawing the next row of data below that tallest item.

The PrintMultiLineData extension method shown in the following code controls the printing process.

// Print the ListView's data at the indicated location
// allowing data to span multiple lines.
public static void PrintMultiLineData(this ListView lvw,
    Point location, Graphics gr,
    Brush header_brush, Brush data_brush, Pen grid_pen)
{
    const int x_margin = 5;
    const int y_margin = 3;
    float x = location.X;
    float y = location.Y;

    // Get the screen's horizontal resolution.
    float screen_res_x;
    using (Graphics screen_gr = lvw.CreateGraphics())
    {
        screen_res_x = screen_gr.DpiX;
    }

    // Scale factor to convert from screen pixels
    // to printer units (100ths of inches).
    float screen_to_printer = 100 / screen_res_x;

    // Get the column widths in printer units.
    float[] col_wids = new float[lvw.Columns.Count];
    for (int i = 0; i < lvw.Columns.Count; i++)
        col_wids[i] = (lvw.Columns[i].Width + 2 * x_margin) *
            screen_to_printer;

    int num_columns = lvw.Columns.Count;
    using (StringFormat string_format = new StringFormat())
    {
        // Draw the column headers.
        string_format.Alignment = StringAlignment.Center;
        string_format.LineAlignment = StringAlignment.Center;
        var header_query =
            from ColumnHeader column in lvw.Columns
            select column.Text;
        DrawMultiLineItems(header_query.ToArray(),
            gr, lvw.Font, header_brush, grid_pen,
            x_margin, y_margin,
            x, ref y, col_wids, num_columns, string_format);

        // Draw the data.
        string_format.Alignment = StringAlignment.Near;
        foreach (ListViewItem item in lvw.Items)
        {
            var subitems_query =
                from ListViewItem.ListViewSubItem subitem
                in item.SubItems
                select subitem.Text;
            DrawMultiLineItems(subitems_query.ToArray(),
                gr, lvw.Font, data_brush, grid_pen,
                x_margin, y_margin,
                x, ref y, col_wids, num_columns, string_format);
        }
    }
}

PrintMultiLineData is an extension method that extends the ListView class. It takes as parameters a Point giving the upper left corner where drawing should begin, the Graphics object on which to draw, and brushes and pens to use when drawing.

The method first gets the screen’s horizontal resolution and uses it to calculate a scale factor for converting from the pixels used to measure column widths to printer units. (For more information, see my previous post.

Next the code copies the ListView control’s column widths into an array, adding some extra room for margins and scaling the result to printer units.

The method makes a StringFormat object to control how text is aligned while printing and then starts printing.

The method uses a LINQ query to select the text displayed by the ListView control’s column headers. It passes an array of those text values, plus some other parameters described shortly, into the DrawMultiLineItems method for printing.

Next, for each row of data, the code uses a LINQ query to select the text values displayed by the sub-items in that row. (Note that the first sub-item contains the main item’s text so you don’t need to treat the item itself as a special case.) The code then calls the DrawMultiLineItems method, passing it the array of sub-item text values plus other parameters.

The following code shows the DrawMultiLineItems method.

// Draw the items in a row.
private static void DrawMultiLineItems(string[] items,
    Graphics gr, Font lvw_font, Brush header_brush, Pen grid_pen,
    float x_margin, float y_margin, float x0, ref float y0,
    float[] col_wids, int num_columns, StringFormat string_format)
{
    float row_height = 0;
    float x = x0;
    for (int i = 0; i < num_columns; i++)
    {
        // Measure the size needed by the text.
        float text_width = col_wids[i] - 2 * x_margin;
        SizeF layout_area = new SizeF(col_wids[i], 1000);
        SizeF row_size =
            gr.MeasureString(items[i], lvw_font, layout_area);
        if (row_height < row_size.Height) row_height = row_size.Height;

        // Draw the text.
        RectangleF rect = new RectangleF(
            x + x_margin, y0 + y_margin,
            text_width, row_size.Height);
        gr.DrawString(items[i], lvw_font,
            header_brush, rect, string_format);

        // Draw the next column.
        x += col_wids[i];
    }

    // Add extra room for the vertical margin.
    row_height += 2 * y_margin;

    // Draw boxes around the column headers.
    x = x0;
    for (int i = 0; i < num_columns; i++)
    {
        // Draw the box.
        RectangleF rect = new RectangleF(
            x, y0, col_wids[i], row_height);
        gr.DrawRectangle(grid_pen, rect);

        // Draw the next column.
        x += col_wids[i];
    }

    // Get ready for the next row.
    y0 += row_height;
}

The DrawMultiLineItems method draws a single row of data items. The variable row_height keeps track of the largest height needed by any item in the row.

For each column in the row, the code uses the Graphics object's MeasureString method to see how much room that column's text needs. If the text needs more vertical space than row_height, the code updates row_height. The code then draws the item's text in the space it requires.

After it has drawn the text for each data item, the code draws boxes around the items. It simply loops through the items drawing the boxes, using the maximum height row_height for each box's height.

After it has drawn all of the boxes, the code adds the row's height to the starting y coordinate y0 so the next row will begin below this one.

This is an improvement on the previous example, but it still has some problems. Most notably, this method assumes that all of the data can fit on one page so it won't break the print out into multiple pages vertically or horizontally. That sort of printing will depend on your specific needs so I won't cover it here. It you need that sort of printing, you can modify this example or email me if you want me to consult for you.

(Note that you may be able to reuse the DrawMultiLineItems method to draw other row of data where items may have different heights.)


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in controls, drawing, graphics, printing | Tagged , , , , , , , , , , , , , , | Leave a comment

Print the contents of a ListView control in C#


[ListView]

The ListView control, like most controls, includes no support for printing. If you want to display a ListView control’s contents on a print out, you need to do all of the printing yourself.

Unfortunately printing in C# is extremely flexible so it’s hard to anticipate what you might want to do with it. For example, suppose a ListView control contains too many columns to fit on one page. Should the program split the print out across multiple pages? Should it print in landscape mode? Should it reduce the print size? Should it ignore some columns that hold less interesting data?

This example displays a print preview of the contents of a ListView control with its View property set to Details. It makes the printed columns in the print out as wide as they currently are in the control.

Depending on your computer, that may not fit well on a printed page. For example, my laptop screen is wider than an 8.5″ x 11″ page so it can easily display a ListView that won’t fit on one page.

This example also assumes that all of the data will fit on one page vertically. If you must print hundreds of entries, you’ll need to modify the code to span multiple pages. (I may make an example like that at some point.)

At this point, you can probably see that any printing program will require a lot of assumptions.

At design time I added a PrintPreviewDialog named ppdListView and a PrintDocument named pdocListView to the program’s form. I also set the dialog’s Document property to pdocListView. When you click the Preview button, the following event handler starts the printing process.

// Print the ListView's contents.
private void btnPreview_Click(object sender, EventArgs e)
{
    // Start maximized.
    Form frm = ppdListView as Form;
    frm.WindowState = FormWindowState.Maximized;

    // Start at 100% scale.
    ppdListView.PrintPreviewControl.Zoom = 1.0;

    // Display.
    ppdListView.ShowDialog();
}

This event handler first casts the PrintDialog into a Form (a PrintDialog is a kind of form so thaht’s allowed) and maximizes it. It then finds the PrintPreviewControl on the dialog and sets its Zoom level to 100%.

The code then calls the dialog’s ShowDialog method to display the dialog modally. Behind the scenes the dialog invokes the PrintDocument to figure out what it should print. The PrintDocument then raises its PrintPage event to let the program tell it what to print.

The following code shows the PrintDocument object’s PrintPage event handler.

// Print the ListView's data.
private void pdocListView_PrintPage(object sender, PrintPageEventArgs e)
{
    // Print the ListView.
    lvwBooks.PrintData(e.MarginBounds.Location,
        e.Graphics, Brushes.Blue,
        Brushes.Black, Pens.Blue);
}

This code simply invokes the ListView control’s PrintData extension method shown in the following code. This is where all the interesting work occurs.

// Print the ListView's data at the indicated location
// assuming everything will fit within the column widths.
public static void PrintData(this ListView lvw, Point location,
    Graphics gr, Brush header_brush, Brush data_brush, Pen grid_pen)
{
    const int x_margin = 5;
    const int y_margin = 3;
    float x = location.X;
    float y = location.Y;

    // See how tall rows should be.
    SizeF row_size = gr.MeasureString(lvw.Columns[0].Text, lvw.Font);
    int row_height = (int)row_size.Height + 2 * y_margin;

    // Get the screen's horizontal resolution.
    float screen_res_x;
    using (Graphics screen_gr = lvw.CreateGraphics())
    {
        screen_res_x = screen_gr.DpiX;
    }

    // Scale factor to convert from screen pixels
    // to printer units (100ths of inches).
    float screen_to_printer = 100 / screen_res_x;

    // Get the column widths in printer dots.
    float[] col_wids = new float[lvw.Columns.Count];
    for (int i = 0; i < lvw.Columns.Count; i++)
        col_wids[i] = (lvw.Columns[i].Width + 4 * x_margin) *
            screen_to_printer;
    
    int num_columns = lvw.Columns.Count;
    using (StringFormat string_format = new StringFormat())
    {
        // Draw the column headers.
        string_format.Alignment = StringAlignment.Center;
        string_format.LineAlignment = StringAlignment.Center;
        for (int i = 0; i < num_columns; i++)
        {
            RectangleF rect = new RectangleF(
                x + x_margin,
                y + y_margin,
                col_wids[i] - x_margin,
                row_height - y_margin);
            gr.DrawString(lvw.Columns[i].Text,
                lvw.Font, header_brush, rect, string_format);
            rect = new RectangleF(x, y, col_wids[i], row_height);
            gr.DrawRectangle(grid_pen, rect);
            x += col_wids[i];
        }
        y += row_height;

        // Draw the data.
        foreach (ListViewItem item in lvw.Items)
        {
            x = location.X;
            for (int i = 0; i < num_columns; i++)
            {
                RectangleF rect = new RectangleF(
                    x + x_margin, y,
                    col_wids[i] - x_margin, row_height);

                switch (lvw.Columns[i].TextAlign)
                {
                    case HorizontalAlignment.Left:
                        string_format.Alignment = StringAlignment.Near;
                        break;
                    case HorizontalAlignment.Center:
                        string_format.Alignment = StringAlignment.Center;
                        break;
                    case HorizontalAlignment.Right:
                        string_format.Alignment = StringAlignment.Far;
                        break;
                }

                gr.DrawString(item.SubItems[i].Text,
                    lvw.Font, header_brush, rect, string_format);
                rect = new RectangleF(x, y, col_wids[i], row_height);
                gr.DrawRectangle(grid_pen, rect);
                x += col_wids[i];
            }
            y += row_height;
        }
    }
}

The static PrintData extension method is contained in the static ListViewExtensions class. The ListView parameter named lvw is the control whose PrintData method is being called. The method takes as parameters the location where the control should be drawn and the Graphics object on which to draw. Normally that’s the Graphics object used by the PrintPage event handler to represent the printed page.

The method also takes parameters giving the brushes that it should use to draw the data’s headers and the data itself, and a pen used to draw a grid around the data. You could add other parameters to specify such things as background colors and fonts, but that would make this method even more complex and it’s already complicated enough for an example.

The code defines constants x_margin and y_margin, which it uses to allow a bit of space between the data items and the grid lines around them. The code initializes variables x and y to be the upper left corner of the area where the control should be printed.

Next the code uses the Graphics object’s MeasureString method to see how tall the header row should be and adds 2 * y_margin to allow a little extra room.

The next step is one of the more confusing. The control on the screen measures in pixels but the printer, and the Graphics object that represents it, measures in 100ths of an inch. To make the grid and other printed elements line up properly, the code needs to translate from screen coordinates to printer coordinates.

To do that, the code creates a new Graphics object associated with the ListView control. That Graphics object is created as if it were going to be used on the screen. The code reads that object’s DpiX property to get the screen’s horizontal resolution in pixels per inch.

The code then divides 100 by the screen resolution to get a scale factor to convert from pixels to 100ths of an inch.

Next the code loops through the ListView control’s Columns collection to make an array named col_wids holding the widths of each column. (The code could look up the widths as needed, but the col_wids array makes the code a little easier to read.)

Finally the code is ready to print. It creates a StringFormat object and prepares it to center text vertically and horizontally.

It then loops through the ListView control’s columns printing each column’s header. To do that, it makes a RectangleF object indicating where the header should be drawn. That RectangleF is located at the current x and y position. It is as wide as the column and as tall as the previously calculated row height.

After printing the header text, the code uses the Graphics object’s DrawRectangle method to draw a rectangle around the text. It then adds the column’s width to the current x value.

After it has drawn all of the headers, the code adds the row height to y to draw the next line of data moved down one row.

Now the program draws the data. For each row, the code resets x to the left edge of the location where the method should print. Next the code loops through the pieces of data in the row, drawing each piece of text and then drawing a rectangle around it.

That’s basically all there is to it, but I did pull a fast one here. The code uses the Graphics object’s DrawRectangle method but, strangely, there is no version of the DrawRectangle method that takes a RectangleF as a parameter. There are versions that take a Rectangle or four int or float values, but none that takes a RectangleF.

To make drawing rectangles easier, I added the following overloaded extension method to the Graphics class.

// Draw a RectangleF.
public static void DrawRectangle(this Graphics gr, Pen pen,
    RectangleF rectf)
{
    gr.DrawRectangle(pen,
        rectf.Left, rectf.Top, rectf.Width, rectf.Height);
}

You could make lots of modifications to this example, but this version should get you started.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in controls, drawing, graphics, printing | Tagged , , , , , , , , , , , , | 24 Comments

Make rectangle extension methods in C#

[rectangle extension methods]

This example shows how to add rectangle extension methods to the Rectangle and RectangleF structs.

The Rectangle and RectangleF structs have several useful properties for determining their geometry such as Left, Right, Top, and Bottom, but they have no midpoint properties. The following code adds MidX and MidY methods to these structs so your code can easily find midpoint values.

public static class RectangleExtensions
{
    public static int MidX(this Rectangle rect)
    {
        return rect.Left + rect.Width / 2;
    }
    public static int MidY(this Rectangle rect)
    {
        return rect.Top + rect.Height / 2;
    }
    public static Point Center(this Rectangle rect)
    {
        return new Point(rect.MidX(), rect.MidY());
    }

    public static float MidX(this RectangleF rect)
    {
        return rect.Left + rect.Width / 2;
    }
    public static float MidY(this RectangleF rect)
    {
        return rect.Top + rect.Height / 2;
    }
    public static PointF Center(this RectangleF rect)
    {
        return new PointF(rect.MidX(), rect.MidY());
    }
}

These methods are contained in the static RectangleExtensions class. They simply calculate the X and Y midpoint coordinates and return them. The Center methods return Point and PointF values giving the rectangles’ centers.

You could easily perform these calculations when you need them, but putting them in extension methods makes them a little easier to use and makes your code easier to read. The following code shows how the program’s Paint event handler draws the shapes shown in the picture.

private void Form1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

    Rectangle rect = new Rectangle(10, 10,
        ClientSize.Width - 20, ClientSize.Height - 20);
    e.Graphics.DrawRectangle(Pens.Red, rect);

    PointF[] points = 
    {
        new PointF(rect.MidX(), rect.Y),
        new PointF(rect.Right, rect.MidY()),
        new PointF(rect.MidX(), rect.Bottom),
        new PointF(rect.Left, rect.MidY()),
    };
    e.Graphics.DrawPolygon(Pens.Blue, points);

    e.Graphics.DrawLine(Pens.Green,
        rect.Center(), new PointF(0, 0));
}

The code creates a RectangleF struct and draws it. It then uses the struct’s MidX, MidY, and Center extension methods to draw the blue diamond and the green line.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in drawing, extension methods, graphics | Tagged , , , , , , , , , , , , , , | Leave a comment

Use string extension methods to validate Social Security numbers in C#

[Social Security numbers]

This example defines three extension methods that return true if strings contain Social Security numbers.

Recall that you must add extension methods to a static class and that the methods must be static. This example begins by defining a Matches string extension method to determine whether a string matches a regular expression.

using System.Text.RegularExpressions;
...
public static bool Matches(this string value, string expression)
{
    return Regex.IsMatch(value, expression);
}

This code simply invokes the Regex class’s static IsMatch method passing it a string and a regular expression. That method returns true or false to indicate whether the string matches the expression. The extension method simply returns that result.

Once you’ve defined the Matches method, it’s easy to make other extension methods that validate particular formats. The following code shows how this example validates Social Security numbers with or without dashes, or with either format.

public static bool IsValidSsnWithDashes(this string value)
{
    return value.Matches(@"^\d{3}-\d{2}-\d{4}$");
}

public static bool IsValidSsnWithoutDashes(this string value)
{
    return Regex.IsMatch(value, @"^\d{9}$");
}

public static bool IsValidSsn(this string value)
{
    return value.Matches(@"^(?:\d{9}|\d{3}-\d{2}-\d{4})$");
}

These methods differ only in the regular expressions they use. The first method, IsValidSsnWithDashes, uses the pattern @”^\d{3}-\d{2}-\d{4}$” to match Social Security numbers of the form ddd-dd-dddd where d is any digit. Notice how the code uses the @ symbol to make a verbatim string literal so the backslashes are not treated as special characters in the string.

The initial ^ matches the beginning of the string. The \d token means “any digit.” The {3} means repeat the previous \d token 3 times, so the first part of the expression matches 3 digits at the beginning of a string. The dash - is treated as a literal character so the string must contain a dash. The expression then uses \d and count specifiers again to match 2 digits, a dash, and 4 digits. The final $ matches the end of the string.

The second method, IsValidSsnWithoutDashes, uses the pattern @”^\d{9}$” to match Social Security numbers of the form ddddddddd. This regular expression simply matches 9 digits.

The third method, IsValidSsn, matches Social Security numbers with or without dashes. Its regular expression includes the two previous regular expressions separated by a vertical bar |, which indicates that either one of the patterns can form a match.

With these extension methods, it is easy for the main program to validate Social Security numbers. The main form uses TextChanged event handlers to give each TextBox a yellow background if it does not contain data in the appropriate format. The following code shows how the TextBox that allows either format works.

private void txtEither_TextChanged(object sender, EventArgs e)
{
    if (txtEither.Text.IsValidSsn())
        txtEither.BackColor = SystemColors.Window;
    else
        txtEither.BackColor = Color.Yellow;
}

This code simply calls the IsValidSsn extension method to see if the text has an appropriate format and then sets the control’s BackColor property accordingly.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in extension methods, extensions, regular expressions, strings | Tagged , , , , , , , , , | 2 Comments

Understand the @ symbol in C#

[@ symbol]

The @ symbol can be pretty confusing for some C# developers. I’ve even known a few who have been programming for quite a while but who still have incorrect assumptions about what @ does.

In your code (and only in your code!) a string literal may contain special two-character pairs starting with a backslash \ called “escape sequences” to represent special non-visible characters. For example, \n represents the newline character and \t represents a tab character.

If you want to place a backslash in a string, you need to “escape it” by placing another backslash in front of it so you get \\. For example, the following code puts the string “C:\temp\whatever” in the string variable my_path.

string my_path = "C:\\temp\\whatever";

If you need to type a lot of strings that contain backslashes, this gets pretty annoying. To make things a little easier, C# lets you add the @ symbol in front of a string to create a “verbatim string literal” where backslashes are not interpreted as escape characters. When you do this, you cannot embed special characters such as newlines and tabs within the string. The following code is equivalent to the previous code except it uses a string literal.

string my_path = @"C:\temp\whatever";

Remember that all of this only applies to your code and not to anything that the user enters, for example, in a TextBox or ComboBox. Anything the user types becomes part of the control’s Text property with no escaping and no special meaning attached to the \ character. You do not need to worry about treating escape characters differently in anything the user types because the user cannot enter special characters that way. In other words, the user cannot enter a tab character by typing \t.

To make matters more confusing, C# also allows you to declare a variable with a name that starts with @ to create a “verbatim identifier.” This lets you create variables named after keywords such as for and struct. Of course the variables are actually named @for and @struct so you don’t quite get to name them after the keywords.

This seems like a really bad idea in any case. It will make your code harder to read and understand. Besides, if you really need to name a variable exit, you could use an underscore in front of it to get _exit. Still confusing but at least it doesn’t drag the @ character into things to make them even more confusing.

The reason I’m worrying this issue so much is that I recently saw code similar to the following:

string user_first_name = @txtFirstName.Text;

I’m actually not completely sure what C# thinks it is doing with that @ symbol, but it does let the program continue running. What the programmer thought this did was protect the program from escape symbols, for example if the user entered \t. What it actually does is nothing. (I think it’s completely bizarre that C# even allows this.)

The following code shows how the program demonstrates various string literals and other string issues when it starts.

private void Form1_Load(object sender, EventArgs e)
{
    txtDoubleSlash.Text = "C:\\temp\\whatever";
    txtAtSign.Text = @"C:\temp\whatever";
    txtFirstLabel.Text = label1.Text;
    txtSecondLabel.Text = label2.Text;

    // Some poorly named variables that use @.
    string[] @foreach = { "A", "B", "C" };
    foreach (string _foreach in @foreach)
    {
        Console.WriteLine(_foreach);
    }

    // Adding an @ doesn't change a TextBox's contents.
    Console.WriteLine(txtDoubleSlash.Text);
    Console.WriteLine(@txtDoubleSlash.Text);
}

The code first displays two strings containing embedded backslashes in text boxes. The first statement escapes the backslashes. The second uses a verbatim string literal.

Next the code copies the text from two Label controls into two TextBox controls in the form’s upper left. Notice that the result in the picture shows the values as they appear in the Label controls with no escaped craziness. The values in the Label controls’ Text properties are as they should be and escaping doesn’t apply.

The code then demonstrates a really confusing loop that uses the @ and _ symbols to make variables look like keywords. A bad idea!

The code finishes by displaying the text in the top TextBox with and without the @ symbol added to the statement. The results are the same regardless of whether there are backslashes in the TextBox.

If you enter some text in the TextBox above the button and then click the button, the following code executes.

private void btnShowValue_Click(object sender, EventArgs e)
{
    txtResult.Text = txtEnteredValue.Text;
}

This code displays the value entered in the TextBox. Again notice that it doesn’t need to do anything about escape sequences.

In summary, you only need to worry about escape sequences or the @ symbol in string literals within your code. You don’t need to worry about them in text typed by the user. This program doesn’t demonstrate it, but you also don’t need to worry about them in text that you read from a file or other data source.

And don’t make verbatim identifiers. They’re just plain confusing!

(Sorry to beat this issue to death but I do see a lot of confusion and mythology surrounding this issue.)


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in strings, syntax | Tagged , , , , , , , , , , | 1 Comment

Center a form on the screen at run time in C#

[center a form]

You can center a form at design time by setting its StartPosition property to CenterScreen. Note that you cannot do this in the form’s Load event handler because the form’s position is already set when that event handler executes. You can do it in the form’s constructor, but it’s usually considered bad style to modify the constructor.

To center the form at design time, either in the Load event handler or in some other part of the program, you need another approach to center a form. You could use the size of the form, the size of the screen, and the location and size of the task bar to figure out where to move the form to center it. Fortunately there’s a much easier way to center a form. Simply invoke the form’s CenterToScreen method as in the following code.

this.CenterToScreen();

Sometimes things are a lot easier than you might think, at least if you know what method to use.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in forms | Tagged , , , , , , , | Leave a comment

Understand when a finally block is executed in C#

[finally]

Many programmers don’t understand (and many have forgotten) how the try catch finally block works.


The basic syntax is:

try
{
    // Statements that could cause an error...
}
catch (Exception ex)
{
    // Statements to execute if there is an error...
}
finally
{
    // Statements to execute after the other statements are done...
}

You can have multiple catch blocks that look for different kinds of exceptions. You can even have a catch block that doesn’t declare any kind of exception variable, although then you can’t easily look at the exception, for example to display the exception’s error message.

The statement must include at least one catch block or a finally block, but it doesn’t need to include both. For example, you can have a finally block and no catch blocks.

The focus of this post is on when the finally block is executed. It is always executed when the try statements and possibly catch statements are finished, no matter how the code exits those statements. This example demonstrates some of the many ways code could exit a try-catch-finally block and shows that the finally block is executed in every case. (Almost. More on that a bit later.)

The following code shows all of the cases executed by this example. Comments before each event handler show the results displayed in the program’s ListBox. I know this is a lot of code but it’s quite simple and mostly self-explanatory.

// Run normally without errors.
// Produces:    Statement
//              Finally
private void btnNormal_Click(object sender, EventArgs e)
{
    lstResults.Items.Clear();
    try
    {
        // No error here.
        lstResults.Items.Add("Statement");
    }
    catch (Exception ex)
    {
        lstResults.Items.Add("Error: " + ex.Message);
    }
    finally
    {
        lstResults.Items.Add("Finally");
    }
}

// Use a break statement.
// Produces:    Statement
//              About to break
//              Finally
private void btnBreak_Click(object sender, EventArgs e)
{
    lstResults.Items.Clear();

    for (; ; )
    {
        try
        {
            // No error here.
            lstResults.Items.Add("Statement");

            // Break.
            lstResults.Items.Add("About to break");
            break;

            // The compiler knows that the following code is unreachable.
            lstResults.Items.Add("Never gets here");
        }
        catch (Exception ex)
        {
            lstResults.Items.Add("Error: " + ex.Message);
        }
        finally
        {
            lstResults.Items.Add("Finally");
        }
    }
}

// Use a continue statement.
// Produces:    Statement
//              About to continue
//              Finally
private void btnContinue_Click(object sender, EventArgs e)
{
    lstResults.Items.Clear();

    do
    {
        try
        {
            // No error here.
            lstResults.Items.Add("Statement");

            // Continue.
            lstResults.Items.Add("About to continue");
            continue;

            // The compiler knows that the following code is unreachable.
            lstResults.Items.Add("Never gets here");
        }
        catch (Exception ex)
        {
            lstResults.Items.Add("Error: " + ex.Message);
        }
        finally
        {
            lstResults.Items.Add("Finally");
        }

        lstResults.Items.Add("Never gets here");
    } while (false);
}

// Throw an error.
// Produces:    Statement
//              Error: Specified argument was out of the range of
//                  valid values.
//              Finally
private void btnError_Click(object sender, EventArgs e)
{
    lstResults.Items.Clear();

    try
    {
        lstResults.Items.Add("Statement");

        // Throw an error.
        throw new ArgumentOutOfRangeException();

        // The compiler knows that the following code is unreachable.
        lstResults.Items.Add("Never gets here");
    }
    catch (Exception ex)
    {
        lstResults.Items.Add("Error: " + ex.Message);
    }
    finally
    {
        lstResults.Items.Add("Finally");
    }
}

// Return.
// Produces:    Statement
//              Finally
private void btnReturn_Click(object sender, EventArgs e)
{
    lstResults.Items.Clear();

    try
    {
        lstResults.Items.Add("Statement");

        // Return.
        return;

        // The compiler knows that the following code is unreachable.
        lstResults.Items.Add("Never gets here");
    }
    catch (Exception ex)
    {
        lstResults.Items.Add("Error: " + ex.Message);
    }
    finally
    {
        lstResults.Items.Add("Finally");
    }
}

// Throw an error and then another in the catch block.
// Produces:    Statement
//              Error: Specified argument was out of the range of
//                  valid values.
//              Nested Error: Specified argument was out of the
//                  range of valid values.
//              Nested Finally
//              Finally
private void btn2Errors_Click(object sender, EventArgs e)
{
    lstResults.Items.Clear();

    try
    {
        lstResults.Items.Add("Statement");

        // Throw an error.
        throw new ArgumentOutOfRangeException();

        // The compiler knows that the following code is unreachable.
        lstResults.Items.Add("Never gets here");
    }
    catch (Exception ex)
    {
        lstResults.Items.Add("Error: " + ex.Message);

        // Throw another error.
        try
        {
            throw new ArgumentOutOfRangeException();

            // The compiler knows that the following code is unreachable.
            lstResults.Items.Add("Never gets here");
        }
        catch (Exception inner_ex)
        {
            lstResults.Items.Add("Nested Error: " + inner_ex.Message);
        }
        finally
        {
            lstResults.Items.Add("Nested Finally");
        }
    }
    finally
    {
        lstResults.Items.Add("Finally");
    }
}

// Throw an error and return from within the catch block.
// Produces:    Statement
//              Error: Specified argument was out of the range of
//                  valid values.
//              Finally
private void btnErrorReturn_Click(object sender, EventArgs e)
{
    lstResults.Items.Clear();

    try
    {
        lstResults.Items.Add("Statement");

        // Throw an error.
        throw new ArgumentOutOfRangeException();

        // The compiler knows that the following code is unreachable.
        lstResults.Items.Add("Never gets here");
    }
    catch (Exception ex)
    {
        lstResults.Items.Add("Error: " + ex.Message);

        // Return.
        return;

        // The compiler knows that the following code is unreachable.
        lstResults.Items.Add("Never gets here");
    }
    finally
    {
        lstResults.Items.Add("Finally");
    }
}

// Use Application.Exit to end the application.
// This closes the window so this method displays
// output in the console window.
// Produces:    Statement
//              The code actually gets here!
//              Finally
private void btnExit_Click(object sender, EventArgs e)
{
    try
    {
        Console.WriteLine("Statement");

        // Exit.
        Application.Exit();

        Console.WriteLine("The code actually gets here!");
    }
    catch (Exception ex)
    {
        Console.WriteLine("Error: " + ex.Message);
    }
    finally
    {
        // The code does get here but the window
        // goes away so you can't see messages there.
        Console.WriteLine("Finally");
    }
}

// Use Environment.Exit to end the application.
// This closes the window so this method displays
// output in the console window.
// Produces:    Statement
private void btnEnvExit_Click(object sender, EventArgs e)
{
    try
    {
        Console.WriteLine("Statement");

        // Exit.
        Environment.Exit(0);

        Console.WriteLine("The code actually gets here!");
    }
    catch (Exception ex)
    {
        Console.WriteLine("Error: " + ex.Message);
    }
    finally
    {
        // The code does get here but the window
        // goes away so you can't see messages there.
        Console.WriteLine("Finally");
    }
}

There are two interesting points to note here. First and most importantly, the finally block is always executed in every one of these cases except for Environment.Exit. Many programmers assume statements like return, break, and continue will immediately jump execution to a new location without any intervening steps, but in fact the finally block is executed in every case.

The second interesting point is that the finally block is even executed if you use Application.Exit to immediately stop the program. Environment.Exit, however, halts the program immediately without executing the finally block. It is the only method shown here that doesn’t execute that block.

For that reason, and because it prevents forms from executing their FormClosing and other cleanup events, I recommend that you never use Environment.Exit to end a program. The most eco-friendly way to end a program is to close all of its forms. That gives all of the forms a chance to clean up before they go away.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in syntax | Tagged , , , , , , , , , , , , | Leave a comment

Use a ProgressBar in C#

[example]

This example shows how to use a ProgressBar to show the progress of a long task. This is a very simple example that performs a synchronous task.

I created the ProgressBar at design time. I left its Minimum property set to 0 and its Maximum property set to 100, although you can change those values if you like.

When you click the Go button, the following code executes.

private void btnGo_Click(object sender, EventArgs e)
{
    long max = long.Parse(txtMax.Text, NumberStyles.Any);
    long tenth = max / 10;
    long leftover = max - 9 * tenth;
    prgCount.Show();
    for (int round = 0; round < 9; round++)
    {
        prgCount.Value = round * 10;
        for (long i = 0; i < tenth; i++) { }
    }
    prgCount.Value = 90;
    for (long i = 0; i < leftover; i++) { }
    prgCount.Value = 100;
    tmrHideProgressBar.Enabled = true;
}

This code reads the number you entered in the text box and divides it by 10. It then performs 9 loops. During each loop the program updates the ProgressBar to show the amount of the task that is complete and then counts to 1/10th of the value that you entered.

After it has finished the 9 loops, the program counts out any remaining numbers that you specified. If the total number is evenly divisible by 10, then this is the last 1/10th of the numbers. If the total isn’t divisible by 10, then this is whatever is left over after the 9 loops.

All of these loops just simulate a long task. In a real program you would do something more useful like processing records in a database.

After that last loop, the program is done so it could hide the ProgressBar. Unfortunately if you do that, the ProgressBar disappears so quickly that the user doesn’t see it at 100% done and that seems a bit uncomfortable. (Try it and see.)

To avoid that, the program enables a Timer named tmrHideProgressBar. The following code shows the timer’s Tick event handler.

private void tmrHideProgressBar_Tick(object sender, EventArgs e)
{
    prgCount.Hide();
    tmrHideProgressBar.Enabled = false;
}

This code hides the ProgressBar and then disables the timer. At design time I set the timer’s Interval property to 500 so the ProgressBar remains visible at 100% filled for half a second before disappearing.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in controls, user interface | Tagged , , , , , , , , , , | Leave a comment

Make pop buttons in C#

[pop buttons]

This example produces an interesting visual effect that I call “pop buttons.” The buttons grow and shrink when the mouse moves over them. The technique is remarkably simple and adds some extra interactivity to an otherwise ordinary program.

The program’s form contains a FlowLayoutPanel that contains the buttons. The panel automatically rearranges the buttons as they resize so you don’t need to write any code for that.

When the form loads, the following code saves sizes and fonts that it will use to resize the buttons.

// The sound effect.
private SoundPlayer PopPlayer =
    new SoundPlayer(Properties.Resources.Pop);

// The small and large button sizes.
private Size SmallSize, LargeSize;
private Font SmallFont, LargeFont;

// Set the small and large sizes.
private void Form1_Load(object sender, EventArgs e)
{
    SmallSize = btnOpen.Size;
    LargeSize = new Size(
        (int)(1.5 * btnOpen.Size.Width),
        (int)(1.5 * btnOpen.Size.Height));

    SmallFont = btnOpen.Font;
    LargeFont = new Font(
        SmallFont.FontFamily,
        SmallFont.Size * 1.5f,
        FontStyle.Bold);
}

This code saves a button’s Size and Font properties. It also calculates the Size and Font that the program will use when the mouse is over a button. For this example the large font is also bold. You could change other button properties such as making the font italic, changing the buttons’ ForeColor property, or whatever else you like.

When the mouse enters one of the buttons, the following event handler executes.

// Enlarge the button.
private void btn_MouseEnter(object sender, EventArgs e)
{
    Button btn = sender as Button;
    btn.Size = LargeSize;
    btn.Font = LargeFont;

    // Play the pop sound.
    PopPlayer.Play();
}

This code converts the sender into a Button and sets its size and font. It then plays the Pop sound effect file that I loaded into the project as a resource at design time.

When the mouse leaves a pop button, the following event handler executes.

// Shrink the button.
private void btn_MouseLeave(object sender, EventArgs e)
{
    Button btn = sender as Button;
    btn.Size = SmallSize;
    btn.Font = SmallFont;
}

This code resets the button’s size and font to their original values.

That’s all there is to it. Note that this sort of effect gives some variation to a program but may annoy some users, particularly business users who really aren’t interested in cute effects.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in controls, fonts, user interface | Tagged , , , , , , , , , , , , , , , | Leave a comment