Well, December is here and another Community Year is almost over. Fortunately for me, there are a high number of quality events and user groups within reasonable driving distance, so for 2009 I thought I could swing a presentation a month. It turns out I was mistaken: while I did not present in every month, I actually ended up speaking at 15 events!
- Feb: RVNUG – Using Blend and Visual Studio Together
- Mar: Roanoke Code Camp – Templating and Data Binding in Blend
- April: RVNUG – Styling a WPF/EF Application (with Tolga Balci)
- April: Richmond Code Camp 2009.1 – Using Blend and Visual Studio Together
- May: HRNUG – Using Blend and Visual Studio Together
- May: Nova Code Camp – Using Blend and Visual Studio Together
- June: Blue Ridge Community College – Application Design Careers for Graphic Artists
- August: CHODOTNET – Using Blend and Visual Studio Together
- September: Raleigh Code Camp – Using Blend and Visual Studio Together
- September: Richmond NUG – Using Blend and Visual Studio Together (unscheduled)
- October: Richmond Code Camp 2009.2 – Using Blend and Visual Studio Together & Data Binding in Blend (2 presentations)
- October: Philly Code Camp – Data Binding in Blend
- October: CapArea Silverlight SIG – Silverlight 3 & Blend 3 Launch
- November: CMAP Code Camp – Using Blend and Visual Studio Together & Data Binding in Blend (2 presentations)
- November: RVNUG – Silverlight 3 & Blend 3 Launch
I also had the chance to attend several other events, most for the first time:
- Spring: Roanoke MSDN Road Show
- July: CodeStock
- August: DevLink
- October: Richmond Java User Group (to see Andy Hunt speak)
- November: PDC09
- December: Roanoke MSDN Road Show
And of course, about 20 regular RVNUG and CHODOTNET User Group meetings. I’ve been taking it easy in December, but I’m already looking forward to hitting the road again next year. Here are events I already have on my calendar:
- Jan 12th: HRNUG – Presenting on Silverlight 4
- Jan 30th: Richmond SQL Saturday
- March 13th: Roanoke Code Camp
- March 18th: CHODOTNET (topic TBA)
- April 6th: CMAP NUG (topic TBA)
- May 22nd: Richmond Code Camp 2010.1
- May 19th: Innsbrook NUG (topic TBA)
- June 3rd: Richmond NUG (topic TBA)
- June 24-26: CodeStock
- October 2nd: Richmond Code Camp 2010.2
I’ll be adding more as the year goes. There are a bunch of great Code Camps I don’t have on here yet: Raliegh, NoVa, CMAP, Philly, and more. If you have a User Group and would like to schedule a presentation for the second half of the year, just email me (link is in the right hand sidebar) or hit me up on Twitter (@joelcochran).
No really, Thanks!
I want to say thanks to all of you out there, it’s been a great year for the for the community, and the people make it all worthwhile. Have a great holiday season, and I’ll see you next year!
I had an experience I thought was worth sharing. As much as we all try to write reusable code, we still end up riding the Copy-Paste express more often than we care to admit. (Come on, admit it… you know you do it…) Of course, it helps if you do this with code that actually works…
The Copy-Paste Express
Several months ago, I wrote an application that required a custom Validation Rule for IP Address format validation. It worked great, and that project was the inspiration for my post on Custom Validation Rules. Now, 2 months later, I want the same functionality in a new application. While the ValidationRule class itself is reusable, the XAML code to implement it is not, so to add it to the new application, I copied the XAML over for the IPAddressTextBox. Much to my dismay, when I executed the program the validation did not work.
Knowing that Application 1 worked as desired, I pored over the code and logic, line by line, and they were the same. Since the XAML was a straight copy, they even used the same field and template names. I was pulling my hair out, so I finally went back and read my post, comparing it to the code I had in place. I was able then to find that some of the validation code was missing from the XAML. Now I was really confused: the code on both applications was missing the same critical piece, so how could Application 1 possibly work?
If you don’t see it coming yet, it turns out that Application 1 no longer worked either. I was testing the installed application and not the current copy of the code: when I ran it from Visual Studio, I experienced the same issue. It took me a while to figure out what happened, but in this case my reliance on Blend was the culprit. At some point I used Blend to update the Binding (I don’t remember why). Normally this wouldn’t be a problem, but Custom Validation rules have to be inserted into the XAML manually. By using Blend to update the binding, Blend removed all my custom validation logic.
The lesson here, of course, is not to make assumptions, but more importantly you need to test all changes to an application. In this case, testing the IPAddressTextBox and the Custom Validation had been completed a long time ago, and since the functionality was never intended to be changed, it was never tested after it was complete. And the working copies in the field were correct, so the bug would never have been reported, at least not until another release. Even then, this particular piece of the software is typically only used once when the user configures the application, so even subsequent releases of current installs would never have revealed the issue. Instead, it would have only shown up on a new install or a reconfiguration. Even worse, since this is purely for validation to prevent the user from entering erroneous data, a new user would never realize the functionality was missing: instead, they would just be able to enter any value for an IP Address. So who knows how long this bad code would have been out there, me all the while assuming it worked.
I’m still floundering in the Unit testing area, and I honestly don’t know if Unit testing would have caught this error or not since it was a GUI issue. It does indicate to me that I need to get a better grasp on all things testing: what if this had been a similar but far more serious bug? It also tells me I need to find more ways to get off the Copy-Paste Express. While we’ll never get away from it completely, if I had taken the time to develop a custom control for IPAddressTextBox that implemented the validation, I never would have had this issue. In any case, it really is the little issues that can teach you the most.
I learned something interesting about ListBox and scrolling content this week. In hindsight it is obvious, but trust me: that’s the last thing you want to hear after two hours of beating your head on your keyboard trying to figure out why the stinking ListBox isn’t scrolling. Read on for the gory details.
What I learned is this: if you have an Auto sized ListBox, meaning that it will stretch its Width and Height to match its contents, the ListBox will never produce a Scrollbar. Even if the content stretches far off the window: in that case, it just so happens that the ListBox will also stretch far off the window. Since the content is not larger than the ListBox itself, no Scroll bars.
Obvious, right? Not so: I have recently had several frustrating experiences with the Auto settings for Width and Height. Don’t get me wrong! I use them a lot, and I tell others to do the same because they greatly assist in laying out elements, especially in Grids. The problem comes when they don’t do what I *think* they are going to do. In the case of the ListBox, I was operating under the assumption that they would Stretch the ListBox to fit the available space in the container, and that is not how they behave.
Realizing my error, I understand now that the scrolling behavior is controlled by the relationship of the size of the Content to the defined (as opposed to visible)size of the ListBox itself. In my case, I had the ListBox as the last element of a StackPanel. I needed the ListBox to fill the remaining space, and I needed the Content to scroll vertically.
The Width of the ListBoxItems was set to the width of the ListBox, minus a little to allow for the Scrollbar, so that wasn’t an issue. I wanted the Height to fill the remaining space, but I had no way to bind to the measurement and I wanted to avoid a lot of code behind hijinx. As discussed above, setting it to Auto would actually prevent the desired behavior, so that option was out.
In this particular case, the application is a fixed size, so I was able to set the size of the ListBox manually to fill the remaining space in the StackPanel, and lo and behold my Scrollbar appeared. All was well, or so I thought…
The Case of the Changing StackPanel
In testing, we realized that the element above the ListBox (an Image control) should only be visible when it had an Image to show. So naturally I wired up a ValueConverter and bound the Visibility to a boolean property in the ViewModel reflecting whether or not there was an Image to display.
This worked great for the Image, but an ugly thing occurred with the ListBox. Since its Height was hardcoded, it shifted up in the StackPanel and no longer stretched to the bottom. It look pretty strange just hanging there, Scrollbar happily in view, but a bunch of empty space beneath it.
So just when I thought I had it licked, I’m back in the same boat with the same problem: I need my ListBox to automatically fill all the remaining space in the StackPanel. Wait, what was that? I want a child to fill all remaining space? That sounds familiar…
Enter the DockPanel
Once I got back up from having the ton of bricks fall on my head, I realized that I was using the wrong container! What I really needed in that scenario was a DockPanel. I was just using StackPanel out of habit, I had no specific need for it, and the items within it would never be more than the Image and the ListBox.
So using Blend’s trusty “Change Layout Type” feature, I changed my StackPanel to a DockPanel. I made sure the LastChildFill property was checked and docked the Image control to the Top and set the VerticalAlignment to Top. I then did the same thing for the ListBox and set its Height property to Auto. Running the application gave me exactly the result I was after in the first place: an automatically resizing ListBox restrained to it’s Parent container’s remaining available space.
So aside from learning a lesson about ListBox and scrolling, I also learned that I need to probably pay a little more attention to the container type I am using. Grid and StackPanel have always been my defaults since they cover most scenarios, but I also need to remember we have other options.
Not too long ago, I posted about how to center a Silverlight Application within an HTML page. Last weekend, I was working on a Silverlight application and I wanted to stretch the background brush across the entire browser, but retain the content in a fixed space in the middle of the screen. I could have done this by creating a gradient and then applying it as the background in my HTML/CSS, but I wanted the ease of design and flexibility that I have within Silverlight. Here is what I did to accomplish the trick.
Sizing the UserControl
To begin with, we have to set the width and height properties of the UserControl so that the UserControl will stretch to fill all available space within the browser. We’ll start by setting Width and Height of our UserControl to Auto and the LayoutRoot container to a fixed size with a Background color so we can see it along with our Background work. This way we can tell what effect we are actually having.
[Note: click on the images for full size]
So far, it seems like we are centering, so all we should need to do is add a Background to the UserControl, right? Unfortunately, that will not do what we want. Adding a Background to the UserControl gives us the exact same results. Since the screen shot is the same, I won’t repeat it, but if you are following along at home try it and you should get the same result.
Also, not to be picky, but this is not actually centering: this is setting the HorizontalAlignment and VerticalAlignment properties to their default values of Stretch. The Grid is actually stretching to fill up the available space, but it is still limited to its fixed size, so it gives the appearance of centering. Not to worry, it’s a minor technicality.
Setting the Background
Our goal is for the Background, in this case a GradientBrush, to stretch across the entire surface of the browser window. Above we saw that fixing the LayoutRoot to the size of our desired content won’t allow this to happen. Instead, we’ll need to set the LayoutRoot Width and Height properties to Auto, and set the Background of the LayoutRoot element to the desired Gradient.
Running the application at this point will show our Background filling the entire browser space.
And here is the XAML:
Centering the Content
Now that we have our Background properly visible across the entire surface of the browser, we need to center the Content inside our LayoutRoot Grid. This is easily done by adding another Container to the LayoutRoot to act as a wrapper for our fixed size content. This example shows a Grid, but I initially did it with a Canvas. I’ve added a Black Background color so you can see the content Grid.
Now set the HorizontalAlignment to Center. I think the default VerticalAlignment value of Top looks best, but of course you could center it or add some Margin around the content Grid to suit your preference.
Now just add your content to the internal Grid, and you will have an automatically sized Silverlight page with centered, fixed size content.
Adding a Clipping Region
One last thing you should be aware of: if you are doing any animations with content off screen, using this method will make them visible outside the bounds of your content. While this has some interesting potential, it is probably not the behavior you want.
To correct this, you need to add a Clipping Region to your content Grid. This will ensure that child elements of that Grid are only visible inside its visual boundaries. Since you can’t do this visually, you’ll need to edit the XAML directly. The key here is to set the Clipping geometry, in this case a Rectangle, to be the same width and height as the content Grid.
It’s important to note that since we are letting Silverlight do all the work, you do NOT want to use the HTML and CSS from the previous Centering post. Doing so will result in only the width defined in the CSS being displayed. Instead, just use the default HTML and CSS settings.
I like this approach better since it gives my application an integrated background. It gives me more creative options and more control. Let me know how it works for you!