Tuesday, November 06, 2007

We've got lots of stuff going on with Philly.Net these days.  Here is some news that I thought would be worthwhile.

Next Meeting:  "15 Minutes of Fame" on November 20, 2007 - Instead of having only two speakers, we'll have 10 speakers, each doing about 15 minutes!  We did this last year for our Nov. meeting and we got great feedback so we'll try it again.  I'm looking forward to it, I'll be doing my 15 minutes on LINQ.  For more information, check out the web site

Visual Studio 2008 is Coming Soon - This isn't exactly Philly.Net news but I thought it was worth mentioning.  Check out the Visual Studio Developer Center for the details.  Microsoft announced at TechEd in Barcelona that VS 2008 and .Net Framework will be released this month!

Future Meetings - We've got lots of good stuff coming soon including regular meetings, Code Camps, Pub Nights and some special events.  If you are interested in speaking or sponsoring, please let us know.  We need sponsors and speakers starting with January Code Camp and also the February monthly meeting.  If you have never spoken, I advise you to give it a try.  It is fun and you'll actually learn a lot from the process.

Architects Group - Mitch Ruebush is starting up a User Group for Architects.  Keep an eye out for more information.

We've got some other things that we're working on.  Plans for Code Camp, newsletters and more.  You'll be hearing more about that soon. 

Tuesday, November 06, 2007 8:49:14 PM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, October 25, 2007

I haven't mentioned this recently, there is a NoDeNUG meeting tonight.  As one of the founders, I'm supposed to help promote the group but for some reason I forgot to mention this meeting on my blog.  What makes that even stranger is that I am the presenter tonight!  So if you are in the area, come out tonight to learn about Creating Custom Server Controls.  It's free, and we'll have pizza.

If you want to know more about these meetings, don't rely on my blogging them.  Go to NoDeNUG.org and sign up.  There's no obligation of any kind and you'll get our monthly meeting reminders via email.

Thursday, October 25, 2007 6:05:48 AM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Sunday, October 21, 2007

Some time ago my wife and I found out that our baby, due in Feb, will be a boy!  It's really sinking in that this baby is coming.  As weird as that sounds, my friends with kids say they felt the same way.  I guess it is harder for men, since we aren't actually pregnant.  Now the responsibility of being a parent is starting to kick in. 

As if it isn't bad enough that this poor guy is going to inherit my genes, I now face my first real situation to screw this kid up - picking a name for him.  This is a tough choice for many reasons but my wife and I are discussing a few options.  We've chosen to keep the name a secret.  That's partly because the surprise will be fun, and partly because it shields us from a lot of criticism and suggestions.  If we tell people we're gonna call him "X" people will tell us what they think, good or bad.  But if wait and announce it after he is born, people can't really criticize us, it is too late!

My second dilemma is pretty serious too.  As I write this post, I am watching the NY Giants game.  Yes, I am a fan of the NY Giants, living in the Philadelphia suburbs.  I grew up in central NJ and have always been a big Giants fan.  My wife and her family are, of course, Eagles fans.  So this is a big situation.  Which team in this classic NFL rivalry will my child support?  Well, I am sorry to do this to him, but I plan to encourage him to back the Giants.  I'll try not to share my "anti-Eagles" attitude with him.  So when the Eagles are playing, I'll encourage him to cheer them on (I don't want him to get picked on too much!) but when they are playing NY, I hope he'll side with his old dad and cheer on the Giants.  Of course, he'll eventually make his own decisions so who knows what will happen.

Sunday, October 21, 2007 2:03:17 PM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Wednesday, October 17, 2007

 

Tonight's meeting was sponsored by RDA Corporation.  They provided our dinner (pizza) as well as a $50 Gift Card to Circuit City as a give away!  Making it's first appearance at a Philly.Net meeting was our new coffee maker!  We bought it for Code Camp but now we'll have coffee for our regular meetings.  Enjoy it!  Thanks to Rob for running tonight's meeting.  Bill was out at Microsoft in Redmond (supposedly he's working) so Rob stepped up to run the show and make announcements.

Our next meeting is November 20th.  We are bringing back the "15 minutes of Fame" format that we used last November.  That means we'll have about 9 presenters, each doing a brief 15 minute presentation.  Last year this worked out really well and we got a great response.  If you are interested, please contact Bill or myself. 

UPDATE:  Both of the presenters are from RDA Corporation.  Check out their Technology Corner for information on these presentations and more.  Or click directly to Building an Extranet with Forms-Based Authentication using WSS 3.0/MOSS 2007 or Visual Studio 2005 Tips and Treats

Presenter:  Deepak Gupta, RDA Corporation
Topic:  Building an Extranet with Forms-Based Authentication using WSS 3.0/MOSS 2007

Sorry, I can't summarize this session.  I was busy with Philly.Net business and I missed the whole thing.  It's too bad because I was told that Deepak really knows his stuff on Sharepoint!

Presenter:  Steve Andrews, RDA Corporation
Topic:  Visual Studio 2005 Tips and Treats

Steve started by promising that these tips would be posted here on his blog.  It's a good thing too because he jumped right in with a ton of tips and I can't remember them all.  He started by showed how to customize VS menus and toolbars with a variety of features that aren't there by default.  Then he showed all kinds of shortcuts and settings that I plan on using tomorrow at work.  I've been using Visual Studio since 2002 and I didn't know many of these little tidbits.  The crowd contributed a few tips too and I'm certain that everyone learned something tonight.  As a bonus, Steve did a quick demo of Lutz Roeder's awesome Reflector tool.

We wrapped up with prizes from RDA, O'Reilly, Wrox, Sams, and SourceGear!

Wednesday, October 17, 2007 7:20:14 PM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Tuesday, October 16, 2007

Last night I presented at the Lehigh Valley .Net User Group.  We had a small turnout but it was a good, interactive group.  I'm definitely looking forward to going back there to present again, if they'll have me!  One thing I found out - it is not as far as I thought.  It took about an hour to get there.  That is a little far to drive for a user group meeting but if there is a topic that you really want to learn, it would be worth it.  I'd advise the Lehigh members and the Philly.Net members to keep an eye on each other's schedules.  Of course, for a full day event like a Code Camp, it is definitely worth the drive to come from Lehigh down to Malvern (where Philly.Net hosts Code Camp).

Anyway, in case you forgot, here is where you can get the source code for the presentation.  Even though I used VS2008 for the demo, the zip file contains a VS2005 solution.

Also, here is where you can get some more explanation on the CreateChildControls() vs Render() situation discussed last night.

Once again, thanks to the guys who came out last night.  Hope to see you again soon.

Tuesday, October 16, 2007 6:21:57 AM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, October 08, 2007

Today I am in Boston at the ReMix07 conference.  A team of us from Philly.Net came up together in Bill's van.  It was a pretty comfortable ride and things went pretty well.  Although there was one point where Mark M directed us into a wrong turn in North Jersey.  We ended up in a field where Tony Soprano buries his bodies.  Anyway, we made it to Boston in the end.

This morning started with a keynote by Brad Abrams, Group Program Manager for the .Net Framework.  He showed off some cool examples of Silverlight.  One example I liked was a streaming video application for HSN.  You can watch (I don't usually watch HSN, seriously) the HSN live in the browser.  The cool part is that the video stream is data encoded, so if you click on a "purchase" button within the Silverlight media player it let's you purchase the item that happens to be showing in the video at that moment.  It's a cool idea.  We saw some other samples too.  Tafiti is a cool Silverlight based search engine.  It has some interesting features and is worth checking out.  Also, check out http://silverlight.live.com/ for a free place to host your Silverlight projects.

The Keynote included a really cool demo.  It was very simple but it got the point across.  Brad created a little Silverlight 1.1 application with some animated XAML that has a click event.  The event is handled by .Net code running in the browser (yes, client side).  He of course created this with VS2008 running in Windows.  But then he FTP'd it up to a Linux server.  And then he pulled it down into a browser running on a Mac.  Yes, it seems that this stuff really runs on various platforms in various browsers.  Lastly, he used the Visual Studio debugger to attach to the Mac's browser and stepped into the code running client side on the Mac!  How cool is that?

Today I sat in on presentations by Rocky Lhotka, Jeff Prosise, and Fritz Onion.  Not bad for one day.  Jeff's talk on Silverlight 1.1 was great and had much more detail then the keynote's Silverlight 1.1 samples.  Silverlight on the client runs 300-400 times faster then Javascript!  The Core CLR that will run on in the browser has a lot of functionality including LINQ, RegEx, Reflection, Generics and Threading!  Some stuff was stripped out to make the download small enough, including COM Interop, Remoting, Binary Serialization.  Most of that is stuff that shouldn't be running in the browser anyway.  Jeff talked about the Transparent Model for security, all code is "sandboxed" to run safely. 

A few other things to mention:

1.  All of the presentations I saw today used C# as the .Net language!  Eat that VB.Net guys!  C# rules.

2.  Lindsay is awesome.  I promised I'd say that.

3.  I don't have the photos yet but at dinner last night Mark M got into an argument with the waitress.  She the proceeded to scold him and force him to put on a dress, become a waitress, and take the order from the next table!  It was classic.

Monday, October 08, 2007 4:30:24 PM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, October 03, 2007

Note:  I'm having some problems formatting the code samples inserted into this post.  I write my posts with LiveWriter.  The first few samples are inserted with a pluggin, VSPaste which always worked great for me.  But today the line breaks keep getting removed.  For the larger sample below, I tried to use another pluggin called Code Snippet.  It kept the line breaks but now my indentations are removed! What a pain.  Not sure if the problem is LiveWriter or the addins.  I'll update this when I figure it out.  Anyway...

 

Yesterday I wrote my first extension method and I thought it would make for a good post.  Ironically, yesterday ScottGu posted an extension method sample on his blog.  Are we thinking alike?  Wishful thinking by me, I guess!  Extension methods are one of the cool features you get with .Net 3.0.  You can use them to add functionality to an existing class without extending the class itself, even if the class is sealed.

Before I show my real extension method, here's a simple example for fun.  Extension methods are pretty easy to create.  This method that returns a bool if a date is my birthday:

 public static bool IsMyBirthday(this DateTime date) { if (date.Month == 9 && date.Day == 21) return true; return false; }

The unusual part is  (this DateTime date).  This parameter is the part that hooks this extension method with the Object, in this case a DateTime.  And it acts like a regular parameter because inside the method I can refer to date to get the value.

It gets called as follows:

 DateTime myDate; if (myDate.IsMyBirthday()) return true;
or even:
 if (DateTime.Now.IsMyBirthday()) return true;

The extension method automatically attaches itself to instances of DateTime!  Of course, you have to include a reference to the namespace where the method lives.

OK, how about some real code.  My TimeAgo extension method extends DateTime and returns a string that represents the DateTime compared to Now as "5 minutes ago" or "2 weeks ago", etc.  You could do a lot more with this method.  I'm not getting too carried away with the logic for what is "yesterday" or "last month" and I am not considering time zone differences.  I'm keeping it simple, hopefully you get the idea.  Here is the code and also a test console app:

namespace Utilities
{
 public static class DateExtension
 {
 public static string TimeAgo(this DateTime date)
 {
 TimeSpan timeSince = DateTime.Now.Subtract(date);
 
 if (timeSince.TotalMilliseconds < 1)
 return "not yet";
 
 if (timeSince.TotalMinutes < 1)
 return "just now";
 if (timeSince.TotalMinutes < 2)
 return "1 minute ago";
 if (timeSince.TotalMinutes < 60)
 return string.Format("{0} minutes ago", timeSince.Minutes);
 if (timeSince.TotalMinutes < 120)
 return "1 hour ago";
 if (timeSince.TotalHours < 24)
 return string.Format("{0} hours ago", timeSince.Hours);
 if (timeSince.TotalDays == 1)
 return "yesterday";
 if (timeSince.TotalDays < 7)
 return string.Format("{0} days ago", timeSince.Days);
 if (timeSince.TotalDays < 14)
 return "last week";
 if (timeSince.TotalDays < 21)
 return "2 weeks ago";
 if (timeSince.TotalDays < 28)
 return "3 weeks ago";
 if (timeSince.TotalDays < 60)
 return "last month";
 if (timeSince.TotalDays < 365)
 return string.Format("{0} months ago", Math.Round(timeSince.TotalDays / 30));
 if (timeSince.TotalDays < 730)
 return "last year";
 //last but not least...
 return string.Format("{0} years ago", Math.Round(timeSince.TotalDays / 365));
 }
 }
 class Program
 {
 static void Main(string[] args)
 {
 DateTime date;
 
 date = DateTime.Now.AddSeconds(1);
 Console.WriteLine(date.ToLongDateString() + " Time ago: " + date.TimeAgo());
 date = DateTime.Now.AddSeconds(-5);
 Console.WriteLine(date.ToLongDateString() + " Time ago: " + date.TimeAgo());
 date = DateTime.Now.AddMinutes(-1);
 Console.WriteLine(date.ToLongDateString() + " Time ago: " + date.TimeAgo());
 date = DateTime.Now.AddMinutes(-5);
 Console.WriteLine(date.ToLongDateString() + " Time ago: " + date.TimeAgo());
 date = DateTime.Now.AddMinutes(-59);
 Console.WriteLine(date.ToLongDateString() + " Time ago: " + date.TimeAgo());
 date = DateTime.Now.AddHours(-1);
 Console.WriteLine(date.ToLongDateString() + " Time ago: " + date.TimeAgo());
 date = DateTime.Now.AddHours(-2);
 Console.WriteLine(date.ToLongDateString() + " Time ago: " + date.TimeAgo());
 date = DateTime.Now.AddHours(-23);
 Console.WriteLine(date.ToLongDateString() + " Time ago: " + date.TimeAgo());
 date = DateTime.Now.AddDays(-1);
 Console.WriteLine(date.ToLongDateString() + " Time ago: " + date.TimeAgo());
 date = DateTime.Now.AddDays(-2);
 Console.WriteLine(date.ToLongDateString() + " Time ago: " + date.TimeAgo());
 date = DateTime.Now.AddDays(-7);
 Console.WriteLine(date.ToLongDateString() + " Time ago: " + date.TimeAgo());
 date = DateTime.Now.AddDays(-14);
 Console.WriteLine(date.ToLongDateString() + " Time ago: " + date.TimeAgo());
 date = DateTime.Now.AddDays(-21);
 Console.WriteLine(date.ToLongDateString() + " Time ago: " + date.TimeAgo());
 date = DateTime.Now.AddMonths(-1);
 Console.WriteLine(date.ToLongDateString() + " Time ago: " + date.TimeAgo());
 date = DateTime.Now.AddMonths(-11);
 Console.WriteLine(date.ToLongDateString() + " Time ago: " + date.TimeAgo());
 date = DateTime.Now.AddYears(-1);
 Console.WriteLine(date.ToLongDateString() + " Time ago: " + date.TimeAgo());
 date = DateTime.Now.AddYears(-2);
 Console.WriteLine(date.ToLongDateString() + " Time ago: " + date.TimeAgo());
 
 Console.Read();
 
 }
 }
 
}

 

 

Wednesday, October 03, 2007 8:46:24 PM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, September 28, 2007

This will be the first in series of posts I'll be writing about creating server controls.  I'll try to share some of what I learned from my research while I prepared for a recent presentation. 

With most software development, there isn't always a simple answer to a question.  This is of course true for creating Composite Controls for ASP.Net 2.0.  One area where this was apparent was the proper way to render a control.  Of the many examples I have found on the web it seems that most people put their rendering code within CreateChildControls() but some override the Render() method.  I'll show examples below.  So which is correct?  You know the answer...It Depends!   My personal preference seems to be outside of the norm but I prefer to include rendering code in the Render() method (as in Option A below) unless there is a compelling reason not to.

My sample CompositeControl will have 2 controls within it:

        private TextBox _textBox = new TextBox();
        private Label _label = new Label();

Option A:

        protected override void CreateChildControls()
        {
            Controls.Clear();
            _textBox.ID = "txtBox1";
            _label.ID = "label1";
            Controls.Add(_textBox);
            Controls.Add(_label);
            base.CreateChildControls();
        }
        protected override void Render(HtmlTextWriter writer)
        {
            EnsureChildControls();
            AddAttributesToRender(writer);
            writer.RenderBeginTag(HtmlTextWriterTag.Div);
            writer.AddAttribute(HtmlTextWriterAttribute.Cellpadding, "1", false);
            writer.RenderBeginTag(HtmlTextWriterTag.Table);
            writer.RenderBeginTag(HtmlTextWriterTag.Tr);
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            _label.RenderControl(writer);
            writer.RenderEndTag(); //</td>
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            _textBox.RenderControl(writer);
            writer.RenderEndTag(); //</td>
            writer.RenderEndTag(); //</tr>
            writer.RenderEndTag(); //</table>
            writer.RenderEndTag();
        }

In option A, CreateChildControls is used simple to set properties on the controls and add them to the Controls Collection.  The Render() method takes care of layout.  In particular, I like being able to use the HtmlTextWriterTag enumeration with the RenderBeginTag() method.  By the way, the RenderEndTag() method will "close" whatever tag is next in line to be closed within the nested hierarchy of tags.  Note that the Div tag I render isn't really necessary.  But I want all of my samples to render the same markup, so I put that in.  Use the AddAttribute() method to add attributes to whichever tag is written next after the AddAtttribute() call.  So in this sample, the CellPadding attribute will get written into the table as <table cellpadding="1">.

Option B:

        protected override void CreateChildControls()
        {
            Controls.Clear();
            _textBox.ID = "txtBox1";
            _label.ID = "label1";

            Controls.Add(new LiteralControl("<table cellpadding='1'><tr>"));
            Controls.Add(new LiteralControl("<td>"));
            Controls.Add(_label);
            Controls.Add(new LiteralControl("</td>"));
            Controls.Add(new LiteralControl("<td>"));
            Controls.Add(_textBox);
            Controls.Add(new LiteralControl("</td>"));
            Controls.Add(new LiteralControl("</tr></table>"));
            base.CreateChildControls();
        }

In option B, all of the rendering is done within CreateChildControls().  There is nothing wrong with this method, however, I don't like it as much.  I like my methods to do one thing only.  And since there is a method named Render(), doesn't it make sense to put the render code in it?  Also, within CreateChildControls, you don't get to use the RenderBeginTag() method with the enumerations.  That means more chances for mistakes, in my opinion.  If you are using this method within a CompositeControl, it is not necessary to override Render().  The default implementation of Render() will be called. 

Option C:

        protected override void CreateChildControls()
        {
            Controls.Clear();
            _textBox.ID = "txtBox1";
            _label.ID = "label1";
            
            Table table = new Table();
            table.CellPadding = 1;
            TableRow row1 = new TableRow();
            TableCell cell1 = new TableCell();
            cell1.Controls.Add(_label);
            TableCell cell2 = new TableCell();
            cell2.Controls.Add(_textBox);
            row1.Cells.Add(cell1);
            row1.Cells.Add(cell2);
            table.Rows.Add(row1);

            Controls.Add(table);
            base.CreateChildControls();
        }

Lastly, I put Option C to show what NOT to do (most of the time).  In this case, I have created my Table, Row and Cells as actual controls, not literals.  This is extra overhead and it is not needed because the only purpose for my table is to control layout.  The literal controls in options A and B will render quicker.  However, there are times when you NEED to have your Table, etc, included in the Controls collection.  In those cases, this technique can be used.  Once again, there is no need to override the Render() method with this technique.

Results:

So how does this all render in the browser?  I put this markup into an ASP.Net Page:

    <!--Option A -->
    <cc1:MyControl1 runat="server" ID="mc1" />
    <br />
    ------------------------------------------
    <!--Option B -->
    <cc1:MyControl2 runat="server" ID="mc2" />
    <br />
    ------------------------------------------
    <!--Option C -->
    <cc1:MyControl3 runat="server" ID="mc3" />

In the browser, I used "View Source" and got the following:

        <div id="mc1">
            <table cellpadding="1">
                <tr>
                    <td>
                        <span id="mc1_label1"></span>
                    </td>
                    <td>
                        <input name="mc1$txtBox1" type="text" id="mc1_txtBox1" /></td>
                </tr>
            </table>
        </div>
        <br />
        ------------------------------------------
        <div id="mc2">
            <table cellpadding='1'>
                <tr>
                    <td>
                        <span id="mc2_label1"></span>
                    </td>
                    <td>
                        <input name="mc2$txtBox1" type="text" id="mc2_txtBox1" /></td>
                </tr>
            </table>
        </div>
        <br />
        ------------------------------------------
        <div id="mc3">
            <table cellpadding="1" border="0">
                <tr>
                    <td>
                        <span id="mc3_label1"></span>
                    </td>
                    <td>
                        <input name="mc3$txtBox1" type="text" id="mc3_txtBox1" /></td>
                </tr>
            </table>
        </div>

Looks pretty close, huh?  There was one extra trick I did to make these match up.  First, remember that in Option A, I added an extra <div> tag when I rendered my control.  Without it, my option A control's outer tag would have been <table>.  Either way may work fine in your application.  Second, Options B and C also have the following code included:

        protected override HtmlTextWriterTag TagKey
        {
            get { return HtmlTextWriterTag.Div; }
        }
Without this override, my controls in Options B and C would have an outermost tag of <span> instead of <div>.  Many people prefer to have controls render with <div> tags and this is how to do it!

I hope this information is helpful to you.  Unfortunately, there isn't always a clear answer of which method is best. 

Friday, September 28, 2007 10:34:04 AM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [0]  |  Trackback