The Ternary Operator (My Guilty Pleasure!)

by Justin 28. February 2008 11:37

Most of the time I am "Mr. Best Practice," but I have one flaw—I think the conditional ternary operator is great! Yes, we've heard it before—they are "hard to read" or "they are error prone," but I disagree. If you understand how it works, and you don't over-complicate your syntax, it's not hard to read or error prone at all. In fact, I believe if used correctly it can increase readibility by decreasing code clutter.

What is it? The conditional ternary operator is simply a conditional operator that accepts three operands. It takes a condition, and then depending on that condition returns one of two operands. Here I demonstrate the basic syntax..

variable = condition ? true part : false part;

Here are a few examples that may be easier to grasp..

int i = true ? 0 : 1; // i = 0
int j = false ? 0: 1; // j = 1

 

The ternary statement is basically just a short-hand way of writing five lines of code..

int i; // i = 0
if (true)
    i = 0; 
else
    i = 1; 

 

Do you use VB.NET? Just use the IIf function instead. The following two lines are in different languages (C# and VB.NET, respectively) but they produce the same result.

int i = true ? 1 : 2; // i = 1
Dim i as Integer = IIf(true,  1, 2) ' i = 1

 

Now the problem with the ternary operator is that people sometimes get crazy with it. You can embed a ternary statement inside of another ternary statement, just like you can embed an if inside of another if..

int k = true ? false ? 2 : 5 : 1; // k = 5

 

.. which is the same as ..

int k = true ? (false ? 2 : 5) : 1;

 

.. which is the same as ..

int k;
if (true)
{
	if (false)
		i = 2;
	else
		i = 5; 
}
else
	i = 1;

 

It doesn't stop there, you can put anything inside a ternary that's considered in-line code. That is, anything that doesn't require a line break. Here's a little exercise for you. Work it out in your head, then compile it to see what the answer is. (Of course, you'd never want to do anything like this in a real project!)

bool a = true, b = false, c = true;
bool d = a || b ? c && b ? a || c : b  && c : a || c ? b || c : a && b;

 

As you can see, conditional statements that use the ternary operator can quickly get out of hand, but as long as you don't get crazy they should still be readable. If they're not readable, or readability is questionable, then you should use the classic if/else block instead.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Is Your Server's E-Mail Showing Up in Spam Folders?

by Justin 12. February 2008 10:19

The first step is to make sure your server is not blacklisted, which is pretty easy to do. Just click that link and type in the IP of your server.

The next step is to make sure the domain name of the e-mail address you're sending from routes back to the IP of your SMTP server.

In other words, say your sending e-mail from admin@mysite.com. Open the command line and ping "mysite.com" like this..

C:\Documents and Settings\Justin>ping mysite.com 

Pinging mysite.com [64.136.24.162] with 32 bytes of data:

Reply from 64.136.24.162: bytes=32 time=72ms TTL=240
Reply from 64.136.24.162: bytes=32 time=95ms TTL=240
Reply from 64.136.24.162: bytes=32 time=84ms TTL=240
Reply from 64.136.24.162: bytes=32 time=76ms TTL=240

Ping statistics for 64.136.24.162:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 72ms, Maximum = 95ms, Average = 81ms

We can see that the IP address that routes back to mysite.com is 64.136.24.162.

If your SMTP server is not on this exact same IP your e-mails might be showing up in the spam folders of Hotmail and Gmail. In this case, your SMTP needs to be on 64.136.24.162—the IP of mysite.com. If it's on 64.136.24.163 then don't be surprised if you're showing up as spam.

Why? Because spammers often spoof e-mail addresses to make it harder for them to track. In their e-mail headers spammers might claim their spam is from admin@idontspam.com, but it's really coming from the IP of lovestospam.com. These days, most mail servers will double check the domain name of the "mail from" against the real name of the server. If something looks fishy in the spam folder it goes.

So make sure the IP of your SMTP matches up with the domain name you claim to be sending from.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: ,

The Microsoft IE Web Standards Soap Opera Continues

by Justin 11. February 2008 13:09

Oh Lord!

Remember those DOCTYPE tags that were supposed to tell the browser how to render the content of the page? Well, they've pretty much lost their meaning. Why?

  1. Developers were using DOCTYPE tags for years without understanding their purpose.
  2. Internet Explorer was ignoring the web-standards behind the DOCTYPE.
  3. Developers only tested their pages in IE, possibly before the popularity of Firefox, Opera, Safari, etc.

In a nutshell, it was the developer's ignorance combined with Microsoft's lack of interest in updating Internet Explorer after version 6.0. (Microsoft released IE 1.0 to IE 6.0 in six years, but IE 6.0 to IE 7.0 took more than five years!)

The result? The inability to move Internet Explorer to web-standards without breaking all those sites that suffer from the aforementioned problems. Microsoft is very afraid of "breaking the web," as they say. A lot of people were angry when their pages didn't render "correctly" in IE7, though the browser was trying to rendering their page according to the DOCTYPE they were using, which was basically ignored in the old versions of IE.

Now things are supposed to be getting better. IE8 now passes the Acid 2 test, which is a great step forward for the Microsoft team, but we have to explicitly tell IE to render in standards mode using a new meta tag. If we fail to use this tag IE will still use the old rendering engine from yesteryears.

The New Meta Tag

The meta tag tells the browser which browser version the page was originally designed for.

<meta http-equiv="X-UA-Compatible" content="IE=8" />

In this case, the meta tag says the page was designed for IE8.

However, what frustrates many of us is that IE's default rendering behavior is still going to be the old one. This means that people who don't necessarily know what they're doing are still going to be designing pages for the old rendering engine—indefinately. I find that the world's most commonly-used browser is "opt-in" for web-standards is a little troubling, but it's the only sure way for IE to stay backwards compatible.

It's a little progress at a cost, I guess.

All I know is that I'll still be supporting IE6 and IE7 until their marketshare falls into negligible numbers, which doesn't look to be anytime soon. The one-design-fits-all dream is slightly closer, but still so far away. In the mean time I'm going to start making space on my sites for a new meta tag.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , ,

Convert that DetailsView's LinkButton to a Button

by Justin 7. February 2008 09:52
DetailsView with LinkButtons DetailsView with Buttons

I love .NET's Data Controls. Version 2.0 ushered in several new ones, one of which was the DetailsView. It's great except for one thing, the default buttons for "update", "insert", and "cancel" are LinkButtons! I first noticed this when I was working with the ASP.NET BeerHouse Starter Kit.

I've observed ordinary users trying to use these buttons and it always confuses them. The fact is, clicking text to submit a form is pretty rare, especially if the form is large and requires a lot of information. Almost always a button or a graphic that looks like a button is used. I'm a fan of consistency and intuitive user interfaces, so naturally I wanted to change the LinkButtons to good old-fashioned Buttons.

The problem is related to the AutoGenerateXXXXXButton attributes of the <asp:DetailsView /> control, where XXXXX is "Edit," "Insert," or "Delete." Get rid of them if you're using them. If you don't you'll find that you have two command fields later.

Create an <asp:CommandField /> element under the <Fields> tag of the DetailsView. Set the ButtonType to "Button." That is the most important part. If you don't set it it will default to "Link" and display LinkButtons again. We'll also need to tell it which command buttons to display via the ShowXXXXXButton attribute of the CommandField.  That's pretty much it. Below is an example of the code that generated the second graphic here on the right. The first graphic was the default look-and-feel for the DetailsView.

<asp:DetailsView ID="DetailsView2" runat="server" AutoGenerateRows="False"
    DefaultMode="Edit" DataSourceID="XmlDataSource1" GridLines="none">
    <Fields>
        <asp:BoundField DataField="Vin" HeaderText="Vin" SortExpression="Vin" />
        <asp:BoundField DataField="Make" HeaderText="Make" SortExpression="Make" />
        <asp:BoundField DataField="Model" HeaderText="Model" SortExpression="Model" />
        <asp:BoundField DataField="Year" HeaderText="Year" SortExpression="Year" />
        <asp:BoundField DataField="Price" HeaderText="Price" SortExpression="Price" />
        <asp:CommandField ButtonType="Button" ShowCancelButton="true" ShowDeleteButton="true" 
            ShowEditButton="true" ShowInsertButton="true" />
    </Fields>
</asp:DetailsView>
<asp:XmlDataSource ID="XmlDataSource1" runat="server" DataFile="~/CarList.xml"></asp:XmlDataSource>

 

If you'd rather use an image instead of a Button set ButtonType to "Image." You'll also have to give the URL of the image via the XXXXXImageUrl attribute of the CommandField, where "XXXXX" is the command type. (i.e. Cancel, Update, Insert, etc.)

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , ,

Create a Scaled Thumbnail with GDI+ (i.e. Constrain Proportions)

by Justin 6. February 2008 11:35

GDI+ comes with a function to create a thumbnail, but you must specify the size of the image. I wanted a function that I could pass an image, and the maximum height and width of the thumbnail. The function would then scale the image down to fit within that size; however, it would also retain the same height and width ratio so the thumbnail would not be distorted. Myself and a co-worker of mine (i.e. David Johnston) came up with a simple algorithm, and I coded it out. Note that this function will work not only with BMPs, but also GIF, JPG, PNG, etc—which are all basically compressed forms of a bitmap, and can be read into .NET's System.Drawing.Bitmap class.

Note: Please make sure you import the System.Drawing namespace if you plan on using this function. 

Update: This function uses the GetThumbnailImage method if the image is small (150px dimensions or less), because it produces more visually pleasing results when creating thumbnails. On the other hand, if you try to create a larger image using the GetThumbnailImage method the results will be blocky and overly compressed. This function takes this into consideration so it will always give good results.

C#

/// <summary>
/// Returns a new bitmap resized to fix a maximum size 
/// while still maintaining the correct aspect ratio.
/// </summary>
/// <param name="oldImage">The image to create a thumbnail from.</param>
/// <param name="maxWidth">The maximum allowed thumbnail width in pixels.</param>
/// <param name="maxHeight">The maximum allowed thumbnail height in pixels.</param>
/// <returns>A properly scaled thumbnail image.</returns>
private static Bitmap GetResizedImage(ref Bitmap oldImage, int maxWidth, int maxHeight)
{
    Bitmap newImage = null;
 
    // if the image is too large (i.e. needs to be resized).
    if (oldImage.Width > maxWidth || oldImage.Height > maxHeight)
    {
        // we use ratios to properly constrain proportions of the image.
        decimal imgRatio = (decimal)oldImage.Width / (decimal)oldImage.Height;
        decimal maxRatio = (decimal)maxWidth / (decimal)maxHeight;
 
        // if the image can be scaled down to perfectly fit the max height and max width.
        if (imgRatio == maxRatio)
        {
            newImage = new Bitmap(oldImage, maxWidth, maxHeight);
        }
        else if (imgRatio < maxRatio)
        {
            // Adjust the width to match the maximum height.
            decimal newRatio = (decimal)maxHeight / (decimal)oldImage.Height;
            int newWidth = (int)decimal.Round(newRatio * oldImage.Width);
 
            // if new image is a thumbnail then use the method that produces better thumbnail results.
            if (maxWidth <= 150 && maxHeight <= 150)
                newImage = (Bitmap)oldImage.GetThumbnailImage(newWidth, maxHeight, null, new IntPtr());
            else
                newImage = new Bitmap(oldImage, newWidth, maxHeight);
        }
        else
        {
            // Adjust the height to match the maximum width.
            decimal newRatio = (decimal)maxWidth / (decimal)oldImage.Width;
            int newHeight = (int)decimal.Round(newRatio * oldImage.Height);
 
            // if new image is a thumbnail then use the method that produces better thumbnail results.
            if (maxWidth <= 150 && maxHeight <= 150)
                newImage = (Bitmap)oldImage.GetThumbnailImage(maxWidth, newHeight, null, new IntPtr());
            else
                newImage = new Bitmap(oldImage, maxWidth, newHeight);
        }
    }
    else
    {
        // return a copy because it's smaller than our max size.
        newImage = new Bitmap(oldImage);
    }
 
    return newImage;
}

VB.NET

''' <summary>
''' Returns a new bitmap resized to fix a maximum size 
''' while still maintaining the correct aspect ratio.
''' </summary>
''' <param name="oldImage">The image to create a thumbnail from.</param>
''' <param name="maxWidth">The maximum allowed thumbnail width in pixels.</param>
''' <param name="maxHeight">The maximum allowed thumbnail height in pixels.</param>
''' <returns>A properly scaled thumbnail image.</returns>
Private Shared Function GetResizedImage(ByRef oldImage As Bitmap, ByVal maxWidth As Integer, ByVal maxHeight As Integer) As Bitmap
    Dim newImage As Bitmap = Nothing
 
    ' if the image is too large (i.e. needs to be resized).
    If oldImage.Width > maxWidth Or oldImage.Height > maxHeight Then
 
        ' we use ratios to maintain the proper aspect ratio of the image.
        Dim imgRatio As Decimal = CDec(oldImage.Width) / CDec(oldImage.Height)
        Dim maxRatio As Decimal = CDec(maxWidth) / CDec(maxHeight)
 
        ' if the image can be scaled down to perfectly fit the max height and max width.
        If imgRatio = maxRatio Then
            newImage = CType(oldImage.GetThumbnailImage(maxWidth, maxHeight, Nothing, New IntPtr()), Bitmap)
        ElseIf imgRatio < maxRatio Then
            ' Adjust the width to match the maximum height.
            Dim newRatio As Decimal = CDec(maxHeight) / CDec(oldImage.Height)
            Dim newWidth As Integer = CType(Decimal.Round(newRatio * oldImage.Width), Integer)
 
            ' if new image is a thumbnail then use the method that produces better thumbnail results.
            If maxWidth <= 150 AndAlso maxHeight <= 150 Then
                newImage = CType(oldImage.GetThumbnailImage(NewWidth, maxHeight, Nothing, New IntPtr()), Bitmap)
            Else
                newImage = New Bitmap(oldImage, newWidth, maxHeight)
            End If
        Else
            ' Adjust the height to match the maximum width.
            Dim newRatio As Decimal = CDec(maxWidth) / CDec(oldImage.Width)
            Dim newHeight As Integer = CInt(Decimal.Round(newRatio * oldImage.Height))
 
            ' if new image is a thumbnail then use the method that produces better thumbnail results.
            If maxWidth <= 150 AndAlso maxHeight <= 150 Then
                newImage = CType(oldImage.GetThumbnailImage(maxWidth, newHeight, Nothing, New IntPtr()), Bitmap)
            Else
                newImage = New Bitmap(oldImage, maxWidth, newHeight)
            End If
        End If
    Else
        ' return a copy because it's smaller than our max size.
        newImage = New Bitmap(oldImage)
    End If
    Return newImage
End Function

Currently rated 4.3 by 3 people

  • Currently 4.333333/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , ,

Vertically Aligning Input Fields Using CSS (No Tables!)

by Justin 5. February 2008 20:35

A common design requirement is for the input fields of a form to be vertically aligned, each to the right of some descriptive text. The look is very clean and easily understood by users because of its widespread use.

Those who want to use this form layout along with a purely CSS-based design should try the following technique. Simply float a label element to the left and set its width. I can verify that this works in Firefox, Internet Explorer 6 and 7, Opera, and Safari. For reference I've included aligning input fields using a table so you may compare the differences.

Aligning Input Fields Using CSS

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Aligning Form Fields Using CSS</title>
        <style type="text/css">
            .form-field
            {
                margin-bottom:5px;
            }
            .form-field label
            {
                float:left;
                width:120px;
            }
        </style>
    </head>
    <body>
        <form action="">
            <div class="form-field">
                <label for="name">Name:</label>
                <input id="name" type="text" name="name" />
            </div>
            <div class="form-field">
                <label for="email">E-mail:</label>
                <input id="email" type="text" name="email" />
            </div>
            <div class="form-field">
                <label for="subject">Subject:</label>
                <input id="subject" type="text" name="subject" />
            </div>
            <p>
                <label for="body">Body:</label><br />
                <textarea id="body" name="body" cols="30" rows="6">
                </textarea><br />
                <input type="submit" />
            </p>
        </form>
    </body>
</html>

 

Aligning Input Fields Using a Table

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Aligning Form Fields Using a Table</title>
        <style type="text/css">
            .input-align
            {
                text-align:right;
            }
        </style>
    </head>
    <body>
        <form action="">
            <table style="width:260px">
                <tr>
                    <td>
                        <label for="name">Name:</label>
                    </td>
                    <td class="input-align">
                        <input id="name" type="text" name="name" />
                    </td>
                </tr>
                <tr>
                    <td>
                        <label for="email">E-mail:</label>
                    </td>
                    <td class="input-align">
                        <input id="email" type="text" name="email" />
                    </td>
                </tr>
                <tr>
                    <td>
                        <label for="subject">Subject:</label>
                    </td>
                    <td class="input-align">
                        <input id="subject" type="text" name="subject" />
                    </td>
                </tr>
            </table>
            <p>
                <label for="body">Body:</label><br />
                <textarea id="body" name="body" cols="30" rows="6"> 
                </textarea><br />
                <input type="submit" />
            </p>
        </form>
    </body>
</html>

Currently rated 3.0 by 3 people

  • Currently 3/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: ,

AJAX is great, but not always..

by Justin 4. February 2008 20:10

I've noticed that AJAX has the same affect on people as OOP. Once someone finally grasps the concept(s) they become so excited that they find a way to overuse the technology in a way that demonstrates its weaknesses.

A good example of poor AJAX use is flickr's camera finder feature. You choose a camera and it shows examples of pictures that were taken with the camera.

Video Demonstration: ajax_navigation_issue.wmv (1.47 mb)

  1. Change the "Now showing" drop down box from "interesting pictures" to "night photos."
  2. You'll notice what's obviously an AJAX update.
  3. Click one of the "night" photos.
  4. Now click the back button.
  5. Notice that you're shown the "interesting pictures" again, but the drop down list says "night photos"!

To view the night pictures again you must change the "Now showing" drop down list to something else, then change it back to "night photos" again. Then you'll actually see the "night photos" again. How annoying. I ended up working around this by opening each picture in a new Firefox tab, but how many web users know how to do this?

Someone else that I used to work with done something very similar after he first learned AJAX techniques. It was a gallery feature that had thousands of pictures and used pagination. I would skip through 30 pages looking at thumbnails until I found a picture I liked. Clicking on an image would take us to another page, showing the picture in its full size and giving some basic information about it.

However, when I clicked the back button I was no longer on page 30, but on page 1 again! Really, really annoying and very similar to the problem mentioned above. The ironic part was that the AJAX was updating around 80% of the HTML on the gallery page! I told him, politely, that a good old fashioned post-back would be the best solution here. He resisted because of the amount of work he already put into AJAX calls, and he even talked about fixing it with some incredibly complicated AJAX-based solution, but eventually he agreed with me and removed AJAX from the gallery altogether.

My point isn't that I don't like AJAX, but that AJAX is NOT the be-all-end-all of web development. It is NOT a solution to every problem, or even most of them. AJAX has the potential to lessen the strain on servers by reducing the amount of data needed to be transferred, and also to perform some pretty slick effects that were difficult several years ago, but you need to know when to use it. Before you ever take on an AJAX-based solution you need to make sure it will improve the user's experience, not make it worse. If you get nothing else from this entry, just remember to always be careful when mixing AJAX with navigation.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: ,

Powered by BlogEngine.NET 1.4.5.0
Theme by Mads Kristensen