Search
On this page
Archives
RSS 2.0 Categories
Blogroll
Disclaimer
Powered by: newtelligence dasBlog 2.0.7226.0
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.
Send mail to the author(s) E-mail
Prism Presentation – Code and Slides#

I recently had the pleasure of speaking at CodeStock 2009 and was very impressed with the conference overall.  The folks behind this conference put in a lot of work and did a really great job.  I got the chance to see some really good presentations as well.  I look forward to attending CodeStock in the future. 

The code and slides will be posted soon at the CodeStock site, but I wanted to note a few things about the code that I’m including for those that were present for my talk on Prism. 

  1. The AlbumSearch solution included is the one we worked through in the presentation.  In the interest of time, I had skipped the creation of separate folders/namespaces for the Views, ViewModels, etc during the presentation. For the download, I have cleaned that up and placed everything in a much more realistic (cleaner) project structure.
  2. While creating the SearchCommand in the SearchModuleViewModel during the presentation, I had skipped adding a CanExecute handler in the interest of time.  Someone asked me about it later and I promised to provide an example in the download and I have done so.  You’ll notice that the Search button now enables only when there are at least 3 letters typed in the Search Box.  (NOTE:  The only Artist Names defined in my test data are:  Pink Floyd, Mars Volta, and Tool.  Anything else will likely blow up as there is no Exception handling in the demo). 
  3. During the presentation, I mentioned a much larger solution that goes through each concept of Prism such as Modularity (and the various ways to load Modules), UI Composition, etc.  I have included my PrismConcepts solution in the download as well. 
  4. I added a link to a WPF and Silverlight Comparison paper from Wintellect to the Resources slide as promised.

I think that covers it.  Thanks again to the organizers, the sponsors, the presenters, and all the attendees of CodeStock

Here’s the Code and Slides.

Wednesday, July 01, 2009 10:12:42 PM (GMT Standard Time, UTC+00:00)
  Comments [0]  | 
Silverlight UI Rant #2 - ListBoxItem#

Tonight's recipient of my UI Rant is the Silverlight 2 ListBox, or more specifically, the ListBoxItem.  A client recently asked me to provide an alternating row style like the DataGrid for the ListBox.  Now, if you've ever tried to add a border or background to your ListBoxItem, you've seen this:

DefaultlListBox 

No problem, you say, I will simply set the HorizontalContentAlignment of my ListBox to Stretch and all should be good.  When that doesn't do it, you'll probably try creating/editing the ListBox's ItemTemplate....maybe adding a Grid and setting its HorizontalAlignment to Stretch.  This too will fail. 

Turns out, the problem is not with your ItemTemplate or even with the ListBox itself.  The issue is in the container that actually contains your Item and that is the ListBoxItem.  The property on the ListBox that allows you to set a custom style for this ListBoxItem is called ItemContainerStyle.  Armed with this information, you quickly throw together a style for your ListBoxItem, maybe like so: 

<Style TargetType="ListBoxItem" x:Key="ItemContainerStyle">
   <Setter Property="Padding" Value="3" />
   <Setter Property="HorizontalContentAlignment" Value="Stretch" />
   <Setter Property="VerticalContentAlignment" Value="Top" />
   <Setter Property="Background" Value="Transparent" />
   <Setter Property="BorderThickness" Value="1" />
</Style>

And then add that to your ListBox, like so:

<ListBox Margin="8,8,10,8" x:Name="defaultListBox" ItemsSource="{Binding}"
   ItemTemplate="{StaticResource EmployeeItemTemplate}"
   ItemContainerStyle="{StaticResource ItemContainerStyle}"/>

Hit F5 and just about the time you congratulate yourself on solving this, the Silverlight Loading Animation will finish and you'll discover that your ListBox still looks exactly like the original screenshot above.  So, what happened? 

What happened is that the default ControlTemplate for the ListBoxItem has its HorizontalAlignment hard-coded to Left and no matter what you do when setting the properties, it will always be Left.  If you'll do a little diving into the full default style for ListBoxItem, courtesy of SilverlightDefaultStyleBrowser (highly recommended), you'll see exactly what I'm talking about in the ContentPresenter's HorizontalAlignment property:

ListBoxItemDefaultStyle

The good news is that because you have the ability to replace the Template of any control in Silverlight, you can simply "correct" this hard-coded problem by replacing the hard-coded Left value for HorizontalAlignment with {TemplateBinding HorizontalContentAlignment}, so your final new Style would look like this:

<Style TargetType="ListBoxItem" x:Key="StretchedItemContainerStyle">
    <Setter Property="Padding" Value="3" />
    <Setter Property="HorizontalContentAlignment" Value="Stretch" />
    <Setter Property="VerticalContentAlignment" Value="Top" />
    <Setter Property="Background" Value="Transparent" />
    <Setter Property="BorderThickness" Value="1" />
    <Setter Property="TabNavigation" Value="Local" />
    <Setter Property="Template">
       <Setter.Value>
         <ControlTemplate TargetType="ListBoxItem">
             <Grid Background="{TemplateBinding Background}">
                <vsm:VisualStateManager.VisualStateGroups>
                <!-- removed VSM code for brevity  -->
                </vsm:VisualStateManager.VisualStateGroups>
                <Rectangle x:Name="fillColor" Opacity="0" Fill="#FFBADDE9" IsHitTestVisible="False" RadiusX="1" RadiusY="1"  />
                <Rectangle x:Name="fillColor2" Opacity="0" Fill="#FFBADDE9" IsHitTestVisible="False" RadiusX="1" RadiusY="1"  />
               <ContentPresenter x:Name="contentPresenter" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}"  />
              <Rectangle x:Name="FocusVisualElement" Stroke="#FF6DBDD1" StrokeThickness="1" Visibility="Collapsed"  RadiusX="1" RadiusY="1"  />
           </Grid>
       </ControlTemplate>
       </Setter.Value>
    </Setter>
</Style>

Now your ListBoxItem will respect the value you are setting for its HorizontalContentAlignment in your Setter above and your ListBox will finally look like this:

CorrectedListBox

Hope that saves someone a little frustration.  I'll continue on to adding the alternating row style in another post. 

Here is the live sample.

Here is the source code.       

Thursday, February 12, 2009 11:43:12 PM (GMT Standard Time, UTC+00:00)
  Comments [0]  | 
Silverlight UI Rant #1 - DataGrid Last Column Fill#

If you've used the the Silverlight 2 DataGrid, you've no doubt seen this:

silverlightDatagrid01

I really hate when this happens!  I've seen several forum discussions where folks were looking to get rid of this nastiness, so I know I'm not the only one losing sleep over it.  I haven't come across a solution in anything I've seen and so now that I have one, I thought I'd share it. 

I ran into this a few weeks back and tried most of the obvious things with defining the DataGridColumns myself rather than auto-generating them.  In these defined DataGridColumns, I tried setting the Width of the last column to "*" just like you would a standard Grid.ColumnDefinition if you wanted to have it take up the remainder of the space.  This did nothing more than invite my buddy, AG_E_PARSER_BAD_PROPERTY, to show up...again.  It appears that star-sizing isn't yet implemented for DataGridColumn derivatives. 

This morning I was finally able to grab a few minutes to dive into DataGrid and find out what I could do about this.  I decided to create an ExtendedDataGrid and add a LastColumnFill DependencyProperty similar to way the DockPanel has a LastChildFill. Most of the work is happening in this method which is called if the LastColumnFill is true:

private void AdjustLastColumnWidth(Size finalSize)
{
    // get the Vertical ScrollBar
    ScrollBar scrollBar = this.GetTemplateChild("VerticalScrollbar") as ScrollBar;

    // compute the width to allow for the scrollbar based on it's visibility.
    double scrollBarWidthAllowance = (scrollBar != null && scrollBar.Visibility == Visibility.Visible) ? scrollBar.ActualWidth + 2 : 2;

    // compute the width of all the columns excluding the last one
    var widthOfAllButLastColumn = this.Columns
                   .TakeWhile(c => c != Columns.Last() &&
                                            c.Visibility == Visibility.Visible)
                   .Sum(c => c.ActualWidth);

     // set the last column width    
     this.Columns.Last().Width = new DataGridLength(finalSize.Width - widthOfAllButLastColumn - scrollBarWidthAllowance);
}

This is the result:

silverlightDatagrid02

Much better!  The live demo shows it with and without a vertical scrollbar.  Note that it also handles auto-generated DataGridColumns if that's your thang.

Here's the live demo.

Here's the code.

Friday, February 06, 2009 2:15:10 AM (GMT Standard Time, UTC+00:00)
  Comments [0]  | 
HtmlPage.PopupWindow vs. HtmlWindow.Navigate#

I was recently looking at various ways of launching an external window from inside a Silverlight 2 application.  Dusting off your javascript brain cell, you'll recall that to open a popup dialog in "the old days", we'd use window.open().  I knew about the HtmlBridge available in Silverlight 2 and I had used it for several other nifty interactions between my managed code and the DOM.  So, I went looking for an equivalent to window.open() and came across the HtmlPage.PopupWindow() method.  If you'll recall the javascript window.open() method is defined as such:

window.open( [sURL] [, sName] [, sFeatures]);

The HtmlPage.PopupWindow() is defined as:

HtmlPage.PopupWindow(string navigateToUri, string target, HtmlPopupWindowOptions options);

Perfect!  ...or so I thought.  I fully expected that if I called PopupWindow() like this:

HtmlPopupWindowOptions options = new HtmlPopupWindowOptions()
            {
                Directories = false,
                Location = false,
                Menubar = false,
                Status = false,
                Toolbar = false,
            };
HtmlPage.PopupWindow(new Uri("http://www.wintellect.com, "_blank", options);

..that I'd get a new browser window with the default width/height on the monitor that the launching browser is on.

After all, if I called window.open() with equivalent arguments as follows that's what would happen:

string features = String.Format("directories=no,location=no,menubar=no,status=no,toolbar=no");
HtmlPage.Window.Navigate(new Uri("http://www.r2musings.com, "_blank", features);   

Instead, I get a small window that launches on Monitor 1.  I do my main work on my Monitor 2 and I kept waiting for my popup window only to realize that it was on the other monitor.  I really hate applications that do this!

Looking into Reflector, the issue seems to be that if options is passed as null in the last parameter of PopupWindow(), the call is simply forwarded to window.open().  But, if you pass an instance of HtmlPopupWindowOptions (even with no properties set) to PopupWindow(), the ToFeaturesString() that gets called to convert this strongly-typed version of the features to the string that is needed for window.open() is also changing the height/width/top/left of the popup window. 

Looking over the documentation...yes, I'm male and sometimes do that *after* nothing else works. ....anyway, there it is in the remarks of HtmlPage.PopupWindow().  All the ugly details and the admission that my popup would be altered.  Documented or not, it's not acceptable to my client and I'm not putting my name on anything that launches a browser on the wrong monitor!    

That's when I decided to have another look at HtmlWindow.Navigate() which seems to more accurately mirror the behavior that I would expect out of something that purports to wrap window.open().  Going this route, we lose the strong typing of the HtmlPopupWindowOptions, but in exchange we get exactly what we are expecting when calling window.open().  The call using HtmlWindow.Navigate() looks like this:

    string features = "directories=no,location=no,menubar=no,status=no,toolbar=no";
    HtmlPage.Window.Navigate(new Uri("http://www.r2musings.com, "_blank", features);   

This will fire a new window on the correct monitor and will honor the default settings for width/height/top/left. 

Here's the code.

Here's a live sample.

Wednesday, February 04, 2009 4:15:15 AM (GMT Standard Time, UTC+00:00)
  Comments [0]  | 
Yngwie Malmsteen syndrome (Silverlight 2 Scroller revisited)#

Earlier this month, I blogged about a Silverlight 2 Scroller control that I had labored over for the better part of a weekend.  The entire time I was working on this Scroller, I had this small, dirty feeling that what I had created was somehow way more than what I needed to accomplish my end goal.  But, time was short, it got the job done and I figured that I could always revisit it at some point.  

Fast forward a few days as I was reading Shawn Wildermuth's blog and I come across his post on the Silverlight ItemsControl and realized what that dirty feeling was all about.  I was exactly the guy he was talking about that was trying to bastardize the Silverlight ListBox into something else...namely the ItemsControl.  So, I revisited the Scroller and was able to remove about 50% or more of the code and still achieve my goal.  No custom ListBox, etc. 

I think it's part of most any process, really.  As you work on making something better you tend to keep adding and adding more code until you reach a saturation point where you need to step back and just start removing things. 

It made me think of so many guitarists in the 80's that just kept adding and adding notes and playing faster and faster until the music just became guitar masturbation instead of anything musical.  (These guys wouldn't have known a whole note if it hit them in the face). On the other hand, you take someone like David Gilmour that can play one note and absolutely convey way more than the shred monsters could ever muster.  It's all part of the learning process.  There's a curve graphed somewhere (I'm sure) that shows the guitarist's ascension to knowing when NOT to play.

So, who is Yngwie Malmsteen and what does he have to do with this post?  You can find out more than you ever wanted to know about Yngwie here.  Yngwie was the poster boy for never quite knowing when to stop adding notes and he flashed before my eyes when I looked back and my original Scroller code.  Anyway, thanks Shawn for saving me from that fate. 

The updated code is here.  Here is the live demo.

I'll leave the original code here in case you want to get it and make fun of me. 

Thursday, January 22, 2009 6:39:29 PM (GMT Standard Time, UTC+00:00)
  Comments [0]  | 
Silverlight System.ExecutionEngineException#

Just a quick note that will hopefully save someone the pain that I just went through chasing yet another exception in Silverlight with nothing to go on from Visual Studio.  (I really hope that there is some better feedback coming on Silverlight applications when you hit a runtime error in the future).  Anyway, I was digging in my App.xaml today to do a bit of much-needed clean up and then started getting System.ExecutionEngineException being thrown at runtime.  I was just about to the point of pulling out WinDbg (see this post on that) and I decided that maybe Blend could help me out.  After all, it really does owe me one for all the times it wouldn't load my xaml without telling me why.

So, I opened the project in Blend and sure enough, it gave me the old "Invalid XAML" message that I was expecting when I attempted to open my app.xaml.  However, it also gave me a bunch of errors about not finding properties from one of my styles.  I took a wild shot and clicked the View XAML Code link that Blend offered.  It placed me on a style that I had added earlier and I immediately noticed that I had left off the TargetType attribute.  Adding this cured the problem. 

And for those that just scan for the code...

Bad:

        <Style x:Key="MyButtonStyle">
            <Setter Property="FontSize" Value="10" />
        </Style>

Good:

        <Style x:Key="MyButtonStyle" TargetType="Button">
            <Setter Property="FontSize" Value="10" />
        </Style>

Thursday, January 15, 2009 8:46:11 PM (GMT Standard Time, UTC+00:00)
  Comments [1]  | 
Silverlight 2 Scroller#

Last week I had opportunity to really dive into some fun with a Silverlight 2 ListBox.  It all started with a requirement for a simple Scroller control.  You know, the simple left-to-right scrollers that you see in many applications?  I've seen them in several places, yet when I searched around for a Silverlight version that met my criteria I came up empty.  I have seen many great Image Carousel controls around, but overall the majority of them were not quite "calm enough" for a typical Line of Business application and I wasn't really intending on using images only.  There were some really great "pieces" that I found as I attempted to assemble this control and now that I have a functional version, I thought I'd share it with the community.       

The first challenge here was that I needed to have two horizontal rows of items in the Scroller.  Thanks to a post over at The Problem Solver and the WrapPanel from the Silverlight Toolkit, I was able to pull this off pretty easily.  So, I went to work on a custom template for a ScrollBar.  My initial thought here was that I'd stretch the ScrollBar to the Height of the ListBox, delete the Thumb, make the Background Transparent, and delete the Large Increase/Decrease controls.  This worked great, but the scrolling was what you would typically get when clicking the Small Increase/Decrease portions of a ScrollBar (i.e. the little arrows).  What we really needed was for each click to move to the next/previous column of items. 

At this point, I decided to lose the custom template for the ScrollBar and just go with a pair of RepeatButtons for the Previous/Next buttons so that I could have a little more control over things.  As I didn't want to see the ScrollBar, I had to hide it by setting the HorizontalScrollBarVisibility and the VerticalScrollBarVisibility to Hidden in the ControlTemplate of the ListBox. 

The ScrollViewer (that is part of our ListBox) is what we want to manipulate to give this per-item scroll experience to the user.  There are a couple of important properties of the ScrollViewer that we care about.  First, the ScrollableWidth which represents the width of the area that can be scrolled.  You can envision this as placing all of the columns end-to-end (including those that are scrolled out of sight) and getting the total width.  Secondly, the HorizontalOffset which is simply the indicator of the current scroll position (relative to the entire ScrollableWidth).  Using these two properties and the ItemWidth, we can compute how far to move the ScrollViewer for each click of our Previous/Next buttons. 

Since I needed direct access to the ScrollViewer in my ListBox and its not readily available from the default ListBox, I decided to create a custom control with a ScrollHost property.  I saw this little trick used in the ItemContainerGenerator class of the Silverlight Toolkit (which has some really great utility code along with the awesome controls....well worth your time to investigate that).  Also, since I was using a WrapPanel as my ItemsPanelTemplate and I needed the ItemWidth for my calculations and since WrapPanel just happens to have an ItemWidth property, I decided to expose that as a property as well.  I overrode the PrepareContainerForItemOverride() method in my custom ScrollerListBox in order to set these properties.  This worked pretty well and with a little math and a call to ScrollViewer.ScrollToHorizontalOffset(), I was able to create the scrolling behavior that I needed. 

But....wouldn't it be cool if the scrolling was animated?  ...it is Silverlight after all and every demo that I've ever seen at a conference with Silverlight has animation.  This proved to be a little more difficult as you can't directly animate HorizontalOffset.  While searching for a way to solve that, I came across a really great solution on Rob's Usability Development blog for creating an AnimationHelperControl to give you something to animate.  His post also made use of his excellent AnimateTo extension methods that he describes in another post.

As I didn't want to hard code the amount of time it took to animate the scroll, I added a ScrollTime Dependency Property to the ScrollerControl and was able to set that declaratively in my Page.Xaml.  

I think the final result gives a nice subtle use of animation that doesn't distract the user from their data.  (As an aside...for a REALLY nice usage of animation in a Silverlight application, check out the one that Billy Hollis shows in this video on dnrTV).

My demo uses employees that I've generated in a TestData class and then binds the various fields to the ItemTemplate of my ListBox using standard Silverlight DataBinding.  I was a bit too lazy to create a separate image for each of my employees, so I used the same image for each.  These images could just as easily be streamed from the database, but that's a different post.

Here is the live demo.

Here is the project source.

I have a few more ideas for the ScrollerControl such as the ability to drag between the items (sort of like the iPhone).  Anyway, I'll post those as I implement them. 

Sunday, January 11, 2009 7:44:44 AM (GMT Standard Time, UTC+00:00)
  Comments [0]  | 
Initializing the FROM value of a Silverlight 2 Animation#

Recently, I was attempting to create my own popup dialog. I had specific requirements in mind for this dialog, including: 

  1. I wanted to animate the Width/Height from 0x0 to the ActualWidth/ActualHeight
  2. I wanted to animate the Opacity from 0 to 1
  3. I wanted to animate the Top/Left properties from the point of mouse click (an icon in my case) to the center of the screen and back to the original point of mouse click when the user closed the dialog

All of these are fairly easy to accomplish using a Storyboard with an x:Name specified.  In the case of my requirement #3 above, I merely needed to set the From value of my animation and call the Begin() method, like so (for purposes of illustration, I'll confine this to the Canvas.Left property only...you can apply the same logic to the Canvas.Top property and it's all in the accompanying project):

<Storyboard x:Name="MoveDialogStoryboard">
  <DoubleAnimation
       x:Name="theDialogAnimation"
       Storyboard.TargetName="theDialog" 
       Storyboard.TargetProperty="(Canvas.Left)"
      To="0" Duration="0:0:0.5" />
  </Storyboard>

theDialogAnimation.From = 800;   // this value would actually come from getting the mouse position via GetPosition()
(MoveDialogStoryboard as Storyboard).Begin();

This all works as you would expect.  However, I really liked the idea of isolating all of my dialog states into one place and the Visual State Manager sounded like the perfect solution...that is, until I tried to set the FROM value programmatically and got hit with a NullReferenceException every time I tried to reference my named Animation. 

I tried several things and ended up posting my issue to the Silverlight forum where Shawn Wildermuth was kind enough to offer a solution.  Shawn's solution was to simply set the property to the value before calling GoToState() in my code.  This made perfect sense and I ran off to give it a try.  It worked...once.  My animation would fire once but then appear to be swallowed or ignored on subsequent clicks.  After further investigation, this turned out to be an artifact of the fact that I was never setting my VisualState back to the original state...something you don't have to do when using a Storyboard outside of the Visual State Manager.  So, that fixed that issue and Shawn's solution worked.  However, I didn't really see any way using this solution to animate back to the original point of mouse click.   

Either way, it didn't really satisfy my initial curiosity for WHY I couldn't programmatically set the FROM value when my animation was inside a Visual State Manager, so I pressed on.  Thanks to a couple of blog posts (here and here) and some pretty ugly LINQ, I was finally able to programmatically set the FROM value and have it animate my dialog from the original point of mouse click with a Storyboard inside of a VisualState like so: 

public void ShowDialog(Point startingPosition)
{
     Storyboard storyboard = Utils.FindStoryboard(LayoutRoot, "DialogStates", "Open");
     (storyboard.Children[0] as DoubleAnimation).From = startingPosition.X;
     (storyboard.Children[1] as DoubleAnimation).From = startingPosition.Y;
     VisualStateManager.GoToState(this, "Open", true);
}

// This is the definition of the extension method FindStoryboard() shown above (which is where the real work happens)
public static Storyboard FindStoryboard(this FrameworkElement parent, string groupName, string stateName)
{
     VisualState visualState = VisualStateManager.GetVisualStateGroups(parent)
         .Cast<VisualStateGroup>().Where(group => group.Name == groupName)
         .SingleOrDefault()
         .States.Cast<VisualState>()
         .Where(state => state.Name == stateName)
         .SingleOrDefault();

     if (visualState != null)
         return visualState.Storyboard;    

     return null;    
}

All of that being said, I didn't end up going this route nor do I recommend it.  It's way too brittle and just plain ugly in my opinion.  In the end, I chose to create my Open and Closed Storyboard animations for my popup dialog as standard Resource Storyboards where I don't have to reset the State before calling and I don't have to jump through hoops to set the value and, most importantly, I can set a name for the Animation and directly set the property value.  For the actual "modes" of my dialog (assuming there are multiple views for the dialog), I used the VSM to represent things like EntryView, EditView, etc.  I think this offers a much cleaner solution.

I've put together a quick demo to illustrate both calling the Storyboard directly and using a Storyboard in a VSM.  The live version is here and the project source is available here

Sunday, January 04, 2009 12:23:48 AM (GMT Standard Time, UTC+00:00)
  Comments [0]  | 
Photosynth#

For those that missed the announcement last week, PhotoSynth is live and after a pretty bumpy start looks like you can at least play around with it now.  I've managed to load two of my sets of photos from a trip to the High Sierras a couple of years ago.  It definitely still has its bumps as I had to cancel and restart the synth several times as it would hang indefinitely.  I didn't get really high "synthy" scores as I wasn't taking the photos with PhotoSynth in mind at the time.  However, the PhotoSynth team has supplied a document of points to keep in mind while shooting photos if you intend to make a PhotoSynth out of them.  I can't wait to try it out when I actually shot the photos for synthing.  There are numerous really great examples on the PhotoSynth site, including some shot by the National Geographic Society photographers.  I like that you can go full screen (or full browser) as that really helps make the experience a bit more of an immersive experience.  Also, the slide show and thumbnails really help as well. 

PhotoSynth is now giving 20GB (!) for free to anyone to try PhotoSynth.  It takes a LONG time to use 20GB in JPEGS!  Give it a try. 

Since my photos didn't all relate to one another, PhotoSynth sort of creates mini-PhotoSynths inside each.  You'll want to check the thumbnails page to see the various scenes that it stitched together. 

Here are links to my first two:

High Sierras - Dana Plateau

High Sierras - Saddlebag Lake Area

Thursday, August 28, 2008 2:01:28 PM (GMT Standard Time, UTC+00:00)
  Comments [0]  | 
devLink Conference#

This past weekend a few of us Wintellectuals made the trek Atlanta to Murfreesboro TN to present at the annual devLink conference.  I really can't say enough about the level of professionalism and obvious preparation that went into devLinkJohn Kellar, Tommy Norman, and Leanna Baker and the entire team that made it happen are well deserving of accolades for their accomplishment.  The conference was held on the campus of Middle Tennessee State University which was also perfectly suited for the task.  All of the rooms were nice, large, and well-equipped (even though said equipment was apparently timed to shut off exactly at the 1-1/2 presentation mark).  As a vegetarian, I can't say too much for the food, but that's pretty much on par with any gathering...I've learned to carry plenty or protein bars over the years.  Bottom line, for $50 this absolutely has to be best value for your buck in training (other than Wintellect's DevScovery, of course *smile*). 

While my colleagues, Steve Porter and Keith Rome, offered four really great talks on Silverlight topics, I was there to present on all the new things available with Cascading Style Sheets (sarcasm off).  Actually, my CSS talk went really well and I received lots of good feedback which I'll continue to roll into that presentation.  All sarcasm aside, most web developers (especially those in Enterprise positions) are stuck with CSS for the foreseeable future and this presentation really aims to go through the major areas where I see developers struggling and try and cast some light on how all those pieces play together.  Thanks to all that made it to the talk (standing room only!) and for the emails that I've received since.

I've updated the slides and code with this past weekend's revisions and you can get it here:

CSS Deep Dive for the ASP.NET Developer

I believe that the other presentations will be posted on the devLink website, so keep an eye out for them.  There were a lot of good ones!

Wednesday, August 27, 2008 1:29:59 PM (GMT Standard Time, UTC+00:00)
  Comments [0]  | 
Updated Deep Dive CSS code#

Thanks to all the folks that came to my Deep Dive CSS for the ASP.NET Developer session at this past weekend's Atlanta Code Camp.  I got some really great feedback from the evaluations and will definitely incorporate some suggestions into this presentation in the future. 

The abstract, updated code and slides are available here:

 Deep Dive CSS for the ASP.NET Developer

 

Tuesday, April 01, 2008 9:25:35 PM (GMT Standard Time, UTC+00:00)
  Comments [0]  | 
Top-10 Application-Design Mistakes#

We saw it when the world first discovered Flash and I'm sure we've got a lot of it left to live through with Silverlight, so this is pretty timely advice from the "Godfather of Web Usability" himself, Jakob Nielsen.  This should be required for every web developer.  There are some great links within the post as well, so be sure to click around.

Top-10 Application-Design Mistakes

Wednesday, February 20, 2008 5:52:10 AM (GMT Standard Time, UTC+00:00)
  Comments [1]  | 
Painless Free Annual Credit Reports#

There is finally a (relatively) painless way to receive your Free Annual Credit Report from the Big 3 Credit Agencies.  It is a really good idea to keep your eye on your credit report these days.  The folks at AnnualCreditReport.com have integrated the registration processes for the three Credit Agencies into a seamless wizard type experience.  I was able to print all three of mine in less than 10 minutes.

Friday, January 25, 2008 6:30:24 PM (GMT Standard Time, UTC+00:00)
  Comments [1]  | 
Weather Widget now in the Silverlight.net Showcase#

The Silverlight Weather Widget made it to the Silverlight.net Showcase and is mentioned in the News section of the Home Page.  WooHooo. 

Friday, January 25, 2008 8:07:29 AM (GMT Standard Time, UTC+00:00)
  Comments [1]  | 
The New Generic Kid on the Block - HashSet<T>#

In mathematics, a Set is typically thought of as a collection of distinct objects that is usually defined by some rule that determines whether they are a member of that particular Set.  For example, a Set could be defined to contain "all the odd numbers under 100" or "every number divisible by 2" or whatever.  The main points here being that the objects in a Set are distinct (i.e. NO duplicate objects are allowed) and the objects are not ordered or sorted in any way.  (If you really feel the need to geek out on Set Theory, be my guest).

According to the MSDN Documentation for HashSet, "a set is a collection that contains no duplicate elements, and whose elements are in no particular order."  Sound familiar?  In the .NET Base Class Library, there has never been a true Set class until now with the release of .NET 3.5 and the brand-spanking-new System.Collections.Generic.HashSet<T> class. 

In the past, when we needed to implement a Set in .NET, we sort of bastardized the List<T> or other unsuspecting Collection classes into something like this:

int[] intArray = new int[]{ 1, 2, 5, 7, 4, 1, 7, 9, 8};
List<int> intList = new List<int>();
foreach(int theInt in intArray)
{
  // checking to make sure that the object is not in our List before adding
  //  so we are calling Contains() and then Add() on every time through the loop
  if (!intList.Contains(theInt))
    intList.Add(theInt);
}

What we needed was a Set that would let us just keep adding objects to it and free us from having to worry about it being there first.  A recent example of when I really needed a true Set class was while working on the Weather WidgetThe Weather Channel provides some 40+ images for use in their SDK, yet in the Weather Widget I never need more than maximum of 11 (and usually less as there is usually duplication).  So, I had the idea to dynamically zip the images that I actually needed for a given Zip Code and use that file for my image assets in Silverlight via CreateXamlFromDownloader.  Obviously, I don't want these images duplicated in the zip file.  So, I came up with this:

HashSet<string> assets = new HashSet<string>();
foreach (ForecastDay day in forecast.Days)
{
  // no Exception here if duplicate...it just doesn't add it.
  assets.Add(Server.MapPath(String.Format("~/images/{0}", day.IconDay)));
}
Utility.WriteZipFile(assets.ToArray<string>())

This just scratches the surface of what HashSet<T> is capable of.  There are member methods available for most Set operations, such as IntersectWith(), UnionWith(), IsSubsetOf(), IsSupersetOf(), RemoveWhere(), etc.   Here's a link to all of the HashSet<T> Members.

Recall that being a member of a set depends on some rule that determines this membership.  With the HashSet<T>, you can define your own rule of what it means to be in a Set.  For a good example of defining your own EqualityComparer, see Introducing HashSet<T> from Kim Hamilton on the BCL Team Blog.

So, welcome the New Kid on the Block to the Generic Collections. 

One last random link I had on the subject for those interested in LINQ:
Good side-by-side comparison of the HashSet and LINQ Set Operations

Friday, January 25, 2008 7:53:51 AM (GMT Standard Time, UTC+00:00)
  Comments [0]  | 
A Better Way to Remove a Trailing Slash from a Path#
C#

How many times have you written this to trim a trailing slash from a path:

if (myPath.EndsWith("\\"))   /* or "/" in the case of a URI  */
  myPath = myPath.Substring(0, myPath.Length-1);

Next time, try this:

myPath = myPath.TrimEnd(new char[]{'\\', '/'});

In addition to String.TrimStart() and String.TrimEnd(), there is an overload on String.Trim() that accepts a character array. There are good examples of usage in the MSDN Library.  Here are the links:  

System.String    Trim(char[])    TrimStart(char[])    TrimEnd(char[])

 

Friday, January 18, 2008 5:32:41 AM (GMT Standard Time, UTC+00:00)
  Comments [0]  | 
Back from the Silverlight Tour#

I had a chance to attend the recent Atlanta stop of Wildermuth Consulting’s Silverlight Tour this past week and wanted to offer some quick comments about it here for anyone considering the class. 

Going into the class, I had about 3 weeks of heads-down knowledge of Silverlight 1.0, but I had spent no time at all with Silverlight 1.1 (now 2.0).  I had also read Silverlight 1.0 Unleashed, watched a lot of the webcasts available and I had just (mostly) completed my first Silverlight 1.0 project.   

The 3-day Silverlight Tour begins with Day 1 of mostly concepts and terminology and an introduction into the Expression Suite.  This was mostly review for me, but I still managed several “a-ha” moments during the day as the presenter, Shawn Wildermuth, explained the “why” behind a lot of the concepts and decisions that were made in regards to Silverlight.  It was a good “shoring up” of my skills in the foundations of Silverlight. 

Day 2 was all about the code.  We spent about ½ the day on Silverlight 1.0 and the other ½ on Silverlight 1.1.  We had several labs, lecture, and discussion throughout the day.  (A good mix of the three, in my opinion).  One of the strengths of the class was that when questions would come up, we had the flexibility in the schedule to actually go off on short tangents and explore different ideas as a class.  I walked away from this day with a much better understanding of how the code side of Silverlight works with the design side, as well as, a lot of anticipation for Silverlight 2.0.  

Day 3 was the main reason I had taken the class and Shawn did not disappoint.  One of the things I struggled most with while working through the Weather Widget was how to organize projects and where do I use this method from the AJAX assemblies and where do I use Silverlight, etc.  These are the types of things that just aren’t in books yet, but Shawn has been there, done that and you are getting it first-hand.  We learned about the integration points with ASP.NET Ajax and Silverlight, and even newer technologies such as ASP.NET Data Services and the Entity Framework.   Further, we talked about packaging of Silverlight controls and other ways of thinking about the generation of XAML…ways I hadn’t thought about until then.  Very cool stuff from someone that truly understands the subject matter and takes the time to explain things in such a way as to really help everyone “get it”. 

So, I walk away with a head full of knowledge about all kinds of fun things that will be filling my life over the next year (and dying to tear my entire project for the Weather Widget apart and do it with all the new Best Practices I managed to acquire over the past 3 days)!  

Friday, January 18, 2008 3:49:55 AM (GMT Standard Time, UTC+00:00)
  Comments [1]  | 
Squeeze Your ASP.NET Applications Until They Scream#

A couple of weeks ago, I had the good fortune of catching a webcast from Jeff Prosise of Wintellect entitled:  "Squeeze Your ASP.NET Applications Until They Scream".  I was really impressed with the content and with Jeff's presentation of same.  The event was sponsored by Compuware and they have given me permission to post a link to the presentation. 

Squeeze Your ASP.NET Applications Until They Scream

Friday, January 11, 2008 4:50:52 PM (GMT Standard Time, UTC+00:00)
  Comments [0]  | 
My First Look at the (Silver)Light#

Over the holidays, I was finally able to catch up on some reading and take some time to play with Silverlight 1.0.  The two books that I spent the most time with are ASP.NET Ajax in Action and Silverlight 1.0 Unleashed.  Both of these, I HIGHLY recommend! 

My first project is a Silverlight 1.0 application that I call Weather Widget (for lack of a more exciting moniker).  The Weather Widget will accept a 5-digit US Zip Code and return a 5-day forecast from The Weather Channel.   You can see it in action here:  Weather Widget.  (Note:  This will require the Silverlight 1.0 plug-in).

I also took the time in this project to use (experiment) with a lot of new toys such as: 

·         LINQ to XML (and the XDocument/XElement classes)

·         New C# language enhancements including Automatic Properties, Object Initializers, Implicitly typed variables, etc. 

·         Javascript key events – some hard-learned (and forgotten and now painfully re-learned) lessons to share here

·         Integration of ASP.NET Ajax and Silverlight – my implementation here is rudimentary right now as I’m still sorting through the most efficient blending of these two technologies

·         Integration of DOM Elements with Silverlight (good post from Keith on that topic here)

·         Expression Studio (mostly Blend) -  I have much to say about this (some of which you can read in this discussion in Shawn’s comments here).  Overall, I really like a lot of things about Blend.  I am finding myself there more these days though I miss a lot of things about working in Macromedia (now Adobe) Fireworks (which I have used for MANY years for all of my design work).  One upcoming post I’m working on here is “Top 10 Things I miss from Fireworks while working in Blend”. 

·         Using JSON – I had never used it so now I have

Guess that about covers it.  I’ll link back to the above points as I blog about each. 

I have several things I’m planning to add (and am open to suggestions), but wanted to get it out there in its current state.  Once I am happy with it, I’ll post it to the gallery on the Silverlight.net site. 

Let me know if the Widget blows up…at this point, I’ve tested only on IE7 and Firefox on my laptop (Windows Vista64). 

 

Monday, January 07, 2008 5:25:20 AM (GMT Standard Time, UTC+00:00)
  Comments [8]  | 
Expression Blend December Preview is out#

This page has a list of changes, as well as, a link to get the bits:

http://www.microsoft.com/expression/products/download.aspx?key=blend2preview

 

 

Saturday, December 08, 2007 3:50:31 AM (GMT Standard Time, UTC+00:00)
  Comments [0]  | 
Sharing Folders in Remote Desktop#

Today, I was struggling with getting some code deployed to a client's test server and called him to double-check FTP credentials and such.   He casually mentions having the ability to share your hard drive (and other devices) with a Remote Desktop session.  How many times would that have come in handy?!?!   Anyway, I dug into it further and it works! 

Check out Dan Mork's blog posting on the topic as he does a great job of walking you through the process.  (Make sure and check the comments as there is another really good tip there about saving your Remote Desktop connection with your configuration). 

Wednesday, October 17, 2007 7:52:28 PM (GMT Standard Time, UTC+00:00)
  Comments [0]  | 
Deep Dive: CSS for the ASP.NET Developer#

Thanks everyone for the comments and tips offered after I gave this presentation at Alabama Code Camp, as well as, at the Atlanta Cutting Edge .NET group last week.  I received several "so that's how it works" comments and that was exactly the point of this talk.

Here is the abstract of the presentation:

This will be a thorough discussion of all that is CSS.  Whether you know it as the necessary evil or the great enabler (that just hasn’t quite clicked for you yet), you should walk away with something valuable from this discussion.  I will begin with the basic box model and travel all the way to the holiest of grails (the no tables here, two and three column ASP.NET Master Page layout…yours to take home for free!).  Along the way, we’ll touch on some CSS Best Practices and gotchas in ASP.NET and take a look at the new CSS tools in Visual Studio 2008 (Orcas).

Get the download here.

Note:  The solution file provided is from Visual Studio 2008 (Orcas) Beta 2.  There is nothing .NET 3.5 specific (as most of it is HTML anyway).   

Update 04/01/08:  Updated the download to compile under Visual Studio 2008 RTM

Monday, October 08, 2007 6:38:05 PM (GMT Standard Time, UTC+00:00)
  Comments [2]  | 
Time for T : An Introduction to .NET Generics#

Finally able to grab a minute to post my code and slides from the Introduction to Generics presentation that I did this past weekend at the Alabama Code Camp at the University of Alabama. 

This is the abstract from the presentation:

With the release of the 2.0 version of the .NET Framework, Generics became first class citizens

in the Common Language Runtime.  Yet, many still shy away from using them because of perceived difficulty or other misconceptions.   This presentation will seek to dispel a few of these myths and offer a gentle introduction into using Generics on a daily basis.  Along the way, I’ll also demonstrate language enhancements in the .NET 3.5 runtime that lend themselves nicely to working with Generics. 

 

Get the download here.  

Note:  The code is compiled on Visual Studio 2008 (Orcas) Beta 2.  The only project in the solution that uses .NET 3.5 specific code is the Collections project.  This uses C# 3.5 Automatic Properties and Property Initializers. 

Monday, October 08, 2007 6:24:56 PM (GMT Standard Time, UTC+00:00)
  Comments [0]  | 
Visual Studio 2008 (Orcas) CSS tools#

I just returned from speaking at the Alabama Code Camp 5.0 in Birmingham.  One of my presentations was Deep Dive CSS for the ASP.NET Developer and I had hoped to spend some time on the tools in Orcas for working with Cascading Style Sheets.  Unfortunately, I did not get a chance to do that due to the time constraints, so I wanted to post some of my better links on that subject...

How to: Use the Apply Styles and Manage Styles Windows
http://msdn2.microsoft.com/en-us/library/bb398979(VS.90).aspx

            How to: Use the CSS Properties Window
           
http://msdn2.microsoft.com/en-us/library/bb398902(VS.90).aspx

How to: Use the Direct Style Application Toolbar
http://msdn2.microsoft.com/en-us/library/bb398977(VS.90).aspx

 

Monday, October 08, 2007 5:45:59 PM (GMT Standard Time, UTC+00:00)
  Comments [0]  | 
Generic Methods: Find Controls by Type#

Although this was originally part of my recent Generics presentation, I have received several requests to publish it separately. 

 

The reason that I created this originally was that I found myself often-times wanting a strongly-typed list of all the checkboxes / buttons / etc in my code-behind/beside pages.  There is the Page.FindControl(string id), but that only allows you to get a control by id and it returns a Control.  I wanted something more specific, yet generic enough to use as a Utility.  This was screaming for Generic Methods, so below is what I came up with.

 

I use this constantly and hope that someone else gets some mileage out of it.  If you have improvements, please post them.  For example usage, download the full Generics presentation. 

 

 

using System;

using System.Collections.Generic;

using System.Text;

using System.Text.RegularExpressions;

using System.Web.UI;

using System.Web.UI.WebControls;

 

namespace r2musings.Web.UI.WebControls

{

  public static class Utility

  {

    #region FindControlsByType

   

    /// <summary>

    ///   Returns a generic list of controls of a provided type starting at a

    ///    a provided base control (works recursively)

    ///    Example Usage: 

    ///       List<Button> buttonList = Utility.FindControlsByType<Button>(testPanel);

    ///       This would return a list of all Buttons contained anywhere within testPanel

    /// </summary>

    /// <typeparam name="T">Type of control</typeparam>

    /// <param name="parentControl">Base control to start search</param>

    /// <returns></returns>

    public static List<T> FindControlsByType<T>(Control parentControl) where T: System.Web.UI.Control

    {

      // new up our return list

      List<T> returnList = new List<T>();

 

      // loop through all controls and call internal recursion to

      //   add all controls of type T to the returnList

      foreach (Control childControl in parentControl.Controls)

      {

        InternalFindControlsByType<T>(childControl, returnList);

      }

     

      // return our List<T>

      return returnList;

    }

   

    #endregion

 

    #region Recursion Method

   

    /// <summary>

    ///   Should NOT call this method directly

    ///   This is for the internal recursion of FindControlsByType() 

    /// </summary>

    /// <typeparam name="T">Type of control</typeparam>

    /// <param name="parentControl">Base control to start search</param>

    /// <param name="returnList">List to add Controls</param>

    private static void InternalFindControlsByType<T>(Control parentControl, List<T> returnList) where T: System.Web.UI.Control

    {

      if (returnList == null)

        throw new ArgumentNullException("Null List passed to InternalFindControlsByType");

 

      if (parentControl is T)

      {

        returnList.Add((T) parentControl);

      }

 

      foreach (Control childControl in parentControl.Controls)

      {

        // call this method recursively to get all child controls

        InternalFindControlsByType(childControl, returnList);

      }

    }

   

    #endregion

  }

}

Monday, October 08, 2007 3:07:05 PM (GMT Standard Time, UTC+00:00)
  Comments [0]  | 
Google, Live, MSDN Search within Visual Studio 2008#

Since Matt Ranlett has now harassed me several times for removing the Google/MSDN macro from my blog, I decided to repost it.  I have added Live Search to the mix this time and I have tested all of the searches on Visual Studio 2008 Beta 2. 

 

The background on this was that I was spending a lot of time on Google and MSDN (aren't we all?) and was going back and forth from Visual Studio to the browser, so I decided to try and integrate my searches into Visual Studio.  The resultant experience is that you can highlight any text in Visual Studio and press your assigned keyboard shortcut and receive search results from your favorite search engines WITHIN the Visual Studio IDE.  It really comes in handy! 

 

In the code below, I have provided the URLs for searching against Google, Live, and MSDN.  It should be pretty obvious when you look at the macro what you would need to do to configure any other search engines.  Be sure to uncomment one (and only one) of the

url lines in the code when you setup each macro. 

 

For those not familiar with macros, here are the steps to add a macro in Visual Studio:

 

1)      Go to Tools | Macros | Macros IDE

2)      Once in the Macros IDE, you can create a new Module or you can just add this to the default “My Macros” module. 

3)      To add to My Macros, just right click on it in the Project Explorer and choose Add | Add New Item.  (if you don’t see the Project Explorer, try View | Project Explorer). 

4)      When the Add New Item Dialog shows up, select Code File and enter GoogleSearch and click OK.

5)      Paste the Code for GoogleSearch below into this file and save it.

     Make sure that you uncomment one of the url lines in the code. 

6)      Click Debug | Build and then close the Macros IDE.

7)      Once back in VS2005, click Tools | Customize and click the Keyboard button at the bottom of the Customize Dialog. 

8)      In the Show Commands Containing box, type “macros” and look for an entry that looks like this:  “Macros.MyMacros.GoogleSearch.GoogleSearch”.  (This could be different depending on where you created the macro). 

9)      Once you have the correct macro selected, go to the Press Shortcut Keys box and type whatever keys you want to fire the macro (I used Alt-G for Google, Alt-M for MSDN, Alt-L for Live). 

10)  Click the Assign button and then OK and then finally Close back on the Customize Dialog. 

11) Highlight any text in the IDE and fire off your shortcut key to test. 

12) Repeat for each search macro you want to setup. 

 

 

Here is the final code for the macro:

 

Imports EnvDTE

Imports System.Text.RegularExpressions

 

Public Module GoogleSearch

 

    Sub GoogleSearch()

        Dim url As String

        Dim selectedText As TextSelection = DTE.ActiveDocument.Selection()

 

        If Not String.IsNullOrEmpty(selectedText.Text) Then

            ' uncomment below for Google

            ' url = String.Format("www.google.com/search?q={0}", Regex.Replace(selectedText.Text, "\s{1,}", "+"))

            

            ' uncomment below for MSDN search

' url = String.Format("http://search.msdn.microsoft.com/search/Default.aspx?brand=msdn&query={0}", Regex.Replace(selectedText.Text, "\s{1,}", "+"))

 

' uncomment below for Live search

' url = String.Format("http://search.live.com/results.aspx?q={0}", Regex.Replace(selectedText.Text, "\s{1,}", "+"))

 

            DTE.ExecuteCommand("View.WebBrowser", url)

        Else

            MsgBox("No text selected.")

        End If

    End Sub

 

End Module

Monday, October 08, 2007 1:07:39 AM (GMT Standard Time, UTC+00:00)
  Comments [1]  | 
All content © 2009 , Rik Robinson