Developing For .NET

Real World .NET Methods, Tricks, and Examples

Archive for January, 2008

A Good, practical LINQ example

You may recall that one of my New Year’s Resolutions was to find and participate in a .NET Forum. Well, I have joined several, and have even posted a few times. While perusing the C# Corner forums today, I found this post about not being able to break out of a loop. The code was using one of my favorite techniques for Windows Forms, the ErrorProvider. I like ErrorProvider and use it quite a bit, and I have done what the poster was trying to do many times: loop through the Controls on a Form and find out whether any of them have an active error message. If they do, then I use that information to warn the user or set some Form state so that it is apparent that an error exists.

My answer does not specifically address the issue the poster brought to the table, but the post got me to thinking: we should be able to use LINQ to solve this problem. Here is a typical example of the loop construct:

bool hasErrors = false;
foreach (Control c in this.Controls)
{
    if (!"".Equals(errorProvider1.GetError(c)))
    {
        hasErrors = true;
        break;
    }
}

In looking at this, it appears we have a good case for using LINQ: we have a Collection and we want to query that Collection for information about itself. Seems it should be pretty straightforward, and ultimately it is, but in this particular case it took a little trial and error to hack it out. Since it wasn’t as simple as I originally thought it would be, let’s walk through it in stages.

Build a Queryable Object

The first step is to try and build a LINQ query of all the Controls on the Form:

var q = from c in this.Controls
        select c;

When I tried to compile this, I got an error I did not expect:

Could not find an implementation of the query pattern for source type ‘System.Windows.Forms.Control.ControlCollection’. ‘Select’ not found. Consider explicitly specifying the type of the range variable ‘c’.

Naturally, I reexamined the code and couldn’t find anything odd about it, but what did seem odd was that I knew this.Controls was a Collection, and LINQ is supposed to work on Collections, right? Wrong!

Getting a Sequence from a Collection

If you read my recent LINQ to Objects post you may recall that LINQ does not work on Collections, but rather Sequences. It soon dawned on me that ControlCollection does not qualify as a Sequence because it does not implement IEnumerable<T>, but rather IEnumerable. This led me to uncharted territory: how do I get an IEnumerable<T> from an IEnumerable? Well, there was definitely some trial and error, and a lot of IntelliSense browsing, but I finally figured out an elegant solution.

Microsoft was gracious enough to provide an IEnumerable extension method (my favorite new feature) that will cast an IEnumerable to an IEnumerable<T>. Fittingly, this method is named Cast<T>(). Here is the code that will transform our ControlCollection into a usable Sequence:

var q = from c in this.Controls.Cast<Control>()
        select c;

Now we have a LINQ query object representing all the Controls on our Form.

Querying the Queryable Object

Now that we have a Sequence instead of a Collection to work with, this could come in quite handy. In fact, this would be a good candidate for a ControlCollection Extension Method in its own right. In the meantime, now that we have a queryable object, we have several options for how to complete our task. One way is to query the entire Sequence when we need it. I’m going to use our friend the Lambda Expression to find out if there are any Controls with Errors in the errorProvider:

// Query as needed
MessageBox.Show(q.Count(c => !"".Equals(errorProvider1.GetError(c))) > 0 ? "There are errors!" : "No errors!");

Again we are using a supplied Extension Method called Count<>() and passing it a Func<> defined by our Lambda Expression. If the count is greater than 0, then we have errors, else we do not.

This approach is especially handy if you may need to query the list in multiple ways. In our case, however, we know that this criteria is the only one we will need, so we have the option to embed our Lambda in the LINQ statement itself. To do so, we will use yet another Extension Method called Where:

var q = from c in this.Controls.Cast<Control>()
        .Where(c => !"".Equals(errorProvider1.GetError(c)))
        select c;

You’ll notice that this is the same logic just implemented as part of the LINQ statement. Now our consuming code is a bit simpler because our list is defined as only the items with messages in the ErrorProvider:

// Now we don’t need the Lambda
MessageBox.Show(q.Count() > 0 ? "There are errors!" : "No errors!");

Here is the complete code block:

var q = from c in this.Controls.Cast<Control>()
        .Where(c => !"".Equals(errorProvider1.GetError(c)))
        select c;
MessageBox.Show(q.Count() > 0 ? "There are errors!" : "No errors!");

Hopefully, as you experiment with these new features, you will come to appreciate how they all complement each other. This example turns out to be fairly simple, even though it took a little effort to work through. In it, we have taken advantage of Extension Methods, LINQ, and Lambda Expressions because they all work together. While these are all great additions on their own, the cumulative power they represent is outstanding. I guess .NET really is worth more than the sum of its parts.

12 comments

Expression Web Review

My copy of Microsoft’s “Web Solutions Toolkit”, a special offer alloted to Microsoft Action Pack Subscribers, arrived yesterday. Among other items, the toolkit includes a complete copy of the Microsoft Expression Suite. I installed the Suite and have begun experimenting with Expression Web, and I wanted to share some of it with you.

Right off the bat, the toolkit includes a license key for a 60 day free pass to Total Training Online for Expression Web. I have seen a couple of Total Training videos before, and I am impressed with their quality. I spent a couple hours this morning watching training videos specifically for Expression Web and then this afternoon I developed my first web site using the tool.

I have built probably two dozen web sites over the years. I have made static pages, CGI data driven sites, Servlets and JSPs, and PHP sites. Over the last five years or so, I have focused on XHTML, CSS2, and PHP. More recently than that, I have grown weary of web development. I no longer get excited about web pages, and when people ask me to help with them I rarely accept. Part of this may be because I have always been a WordPad kind of a guy (unless I’m on Linux, where I prefer VI). What can I say, in this area I have always been a bit old fashioned. I like the hands on control it affords me. As an answer to my lost desire to create web sites, over the last year or so I have become a WordPress advocate: if I can’t do it in WordPress, I’m just not interested.

Well, all that is about to change. Expression Web is a fantastic tool. It includes an incredible set of features that are easy to find and easy to use. I find it as intuitive as a complex piece of software could be, and I am very impressed with the CSS editing facilities. Equally impressive are the preview options. Here are some of the other highlights:

  • Web sites can be created from predefined templates
  • You can create and save your own templates
  • Dynamic Web Templates allow you to implement and update the look and feel of an entire site (not the same as ASPX Master Pages)
  • You can create ASPX pages (including Master Pages) – even though you cannot write C# or VB in Expression Web, you can use it to easily create the pages which can then be consumed by Visual Studio. This can even include Data Binding code.
  • If you are into that sort of thing, you can create Tables and Frames. Meh.
  • You can create pages using Absolute Positioning or Relative Positioning
  • The Absolute Positioning tools blow ASPX and Visual Studio out of the water
  • The software includes a ton of templates for CSS layout, pages, tables, even entire web sites

The interface is very similar to Visual Studio, so if you are a VS user you should feel right at home with Expression Web. If you are new to Web design, I think this would be a great way to get your feet wet. If you are an old hat, I think you will understand and love this tool in a matter of minutes. In either case, it is definitely evaluating.

Also worth evaluating is Total Training. I have no interest in their company whatsoever, but so far I like what I see, and they have training available for the entire suite for under $300. I think I’ll be a customer in the very near future. As I learn more, I will certainly share.

No comments

Automatic Properties and StackOverflowException

I’ve written a couple of times before about Automatic Properties, a tiny little feature that I have really come to enjoy. Remember that an Automatic Property looks something like this:

// An Automatic Property
public string FirstName { get; set; }

I’ve also written that if you want to add any behavior to this property, then you must create a variable and complete the code just as you would have a regular property. I was coding the other day and I had to transform add some behavior to what had been an automatic property. For grins, I wanted to see what I could get away with, so I tried a couple of different approaches.

First, I really only wanted to add behavior to the Setter, so I tried leaving the Getter as is:

// Will not compile
public string FirstName
{
    get;
    set
    {
        FirstName = value.TrimEnd(new char[] { ‘ ‘ });
    }
}

This will not compile, resulting in the following error:

‘ConsoleTestBed.Person.FirstName.get’ must declare a body because it is not marked abstract, extern, or partial

OK, so no joy there, I have to fill out the Getter. But notice in the Setter block there is no error! So I fill out the Getter and it looks like this:

// This compiles
public string FirstName
{
    get { return FirstName; }
    set
    {
        FirstName = value.TrimEnd(new char[] { ‘ ‘ });
    }
}

This compiles just fine. What I’m hoping at this point is that the Compiler will recognize what I am doing (given its context) and still create the variable for me. However, when I run it, I get a StackOverflowException. What you have probably figured out, and what I was afraid of, is that by referencing the Property name within the Property, I have created a recursion problem. So, unfortunately, I was originally correct: in order to make these changes work, I have to create a variable to support the Property:

// This compile AND works
private string _firstName;
public string FirstName
{
    get { return _firstName; }
    set
    {
        _firstName = value.TrimEnd(new char[] { ‘ ‘ });
    }
}

So if your program throws a StackOverflowException on a Property, be sure that you haven’t created a Recursion issue. Maybe someday the C# compiler guys can find a way to make this work based on the Context, or maybe a Property Attribute.

No comments

Saving Word 2007 Docs to PDF

This is not really a development issue, but something I found that might interest you.

With my new computer, I recently installed Office 2007 Enterprise (courtesy of our Microsoft Partner Action Pack) on my new Vista machine. I wanted to save a document to PDF, so I searched the help and it indicated that I could.

Unfortunately, the default install did not appear to be capable of doing so, but I found this document at Microsoft, which led me to another page: Enable support for other file formats, such as PDF and XPS. Turns out there is a free plug-in you can install that will enable additional file format support.

A quick Windows Validation, download, and install later and I am now saving docs to PDF. Just thought I would share, hope it helps someone out there.

No comments

Extension Methods Update

I’ve been working on some more Extension Method stuff (I’ll be sharing soon!), and in the process I updated the DevelopingForDotNet.Extensions namespace.  Here is a list of the updated methods:

  • DateTime.GetDateString() – accepts an Enum for the format of the DateTime string (Enum is part of the namespace).  Overridden to allow control over the separator character.
  • DateTime.TwoDigitYear() – returns the Year of the DateTime in two digit format.  Great for aligning with legacy data.
  • IDictionary.ExecuteOnValues<K, V>() – performs an Action<V> on each Value in a Dictionary.
  • decimal.ConvertToMoney() – Converts any decimal to a two decimal precision numeric.  Overridden to allow control over rounding behavior.
  • decimal.GetMoneyString() – Converts a decimal to Money and returns a properly formatted string.
  • decimal.GetUSMoneyString() – implements the above, but specific to US Currency.  Also overridden for rounding.
  • long.ConvertToWords() – converts a long value to spelled out words.
  • decimal.GetDecimalNumbers() – returns just the decimal portion to the right of the decimal point as an integer.
  • StringBuilder.Clear() – clears all text from a StringBuilder (sets its length to 0).

Be sure to download the update.  Keep watching, there will be more to come.

No comments

« Previous PageNext Page »