Tuesday, January 15, 2008

CSS Lessons

I just finished re-skinning a website and came across a couple of CSS stumbling blocks that gave me a little trouble.  Hopefully these my save you some time in your future projects.

My first issue has to do with the position style.  Absolute positioning will place an element at the exact pixel location on the page.  However, if the parent element has a position style of "relative", then the absolutely positioned element will use the parent element to determine position, instead of the page itself.

My other issue revolved around the anchor pseudo classes.  If you assign them directly to the "a" element, they will be used by all the anchors on the page, whether you like it or not.  Consider the following CSS styles:

a:link { color: red; }
a:active { color: red; }
a:visited { color: red; }
a:hover { color: green; }

#mydiv a:link { color: blue; }
#mydiv a:active { color: blue; }
#mydiv a:visited { color: blue; }
#mydiv a:hover { color: yellow; }

In this scenario, all the links in mydiv will be red.  To get around this, you need to put identifiers in front of all the "a" styles.

I experienced this behavior in both IE and Firefox. 

Thursday, January 10, 2008

Microsoft AJAX UpdateProgress Control

Today, I learned that the coconut crab is the largest land-living arhropod in the world, Clinophobia is a fear of going to bed, and you can easily cause an animated gif to display while your ASP.NET AJAX Update panel is busy doing a call back. 

It's easy, just use the UpdateProgress Control.  Point it at the update panel and give it something to display and voila!  Here's a code example:

<asp:UpdateProgress ID="updateProgress1" runat="server" AssociatedUpdatePanelID="UpdatePanel1" DisplayAfter="100" DynamicLayout="true">
<ProgressTemplate>
<div class="Update"><img src="MyAnimated.gif" /></div>
</ProgressTemplate>
</asp:UpdateProgress>

Wednesday, January 09, 2008

Use .NET 3.5 in ASP.NET 2.0

Today, I was able to get an ASP.NET 2.0 application to successfully reference and use a .NET 3.5 dll.  I don't know why this surprised me, but it did.  The dll uses Linq to do some XML parsing among other things.  All I had to do was install the framework on the server.  Sweet!  I may have to rename my site to something like "Frankenstein".  :)

Monday, January 07, 2008

Count things with Linq

I had a situation where I needed to determine how many objects in a generic list were missing a value in a property.  That count was very important to the user.  Basically, I was looking for all the objects in the list that didn't have a value in the path property.  Normally, I would have created a count integer and a loop of some sort and just counted. 

int count = 0;
foreach(Profile p in Profiles)
{
if(String.IsNullOrEmpty(p.Path))
{
count++;
}
}



I could have also used an anonymous delegate, but I was playing with Linq and found this little short cut.



int count = (from p in profiles where String.IsNullOrEmpty(p.Path) select p).Count();



I think that this is much cleaner and easier to read.   Happy Linq'n!

Friday, January 04, 2008

Multiple Using Statements

Using statements are used to define a scope on an object that implements the iDisposable interface.  It automatically calls the Dispose method on the object when it goes out of scope.

Here's a neat little trick to deal with nested using statements.  Consider the following code snippet that has a couple of them:

using (FileStream fs = File.Create("File.txt"))
{
using (TextWriter tw = new StreamWriter(fs))
{
tw.WriteLine("The content of my file!");
}
}



Here's a cleaner, and in my opinion easier, way to write these.  Notice that the FileStream object is useable when creating the TextWriter object.



using (FileStream fs = File.Create("File.txt"))
using (TextWriter tw = new StreamWriter(fs))
{
tw.WriteLine("The content of my file!");
}



If you are instantiating multiple objects of the same type, you could put them all on one line.  It is harder to read this way, but maybe that's just me. ;)



using (StreamWriter tw1 = File.CreateText("W1"), tw2 = File.CreateText("W2"))
{
tw1.WriteLine("The content of my first file!");
tw2.WriteLine("The content of my second file!");
}

Thursday, January 03, 2008

Databinding a Generic List to a WPF ListView

Inevitably there will come a time when you will want to start using the WPF framework for your business apps, and that means that you'll need a grid.  The WPF grid of choice is the ListView control. 

The ListView control is extremely powerful, flexible and customizable.  It's also way complicated!  On the Microsoft campus, in the basement, past the closet where they hide the Steve Balmer bobble-heads and the unused copies of Microsoft BOB, from a darkened cubicle, a developer is laughing at us.

Anyway, there are not a lot of examples of how to programmatically bind a generic list to a ListView control.  So, here's mine.

First let's take a look at the class that we want to add to the collection:

namespace MyNameSpace
{
public class Item
{
public string Description { get; set; }
public string Name { get; set; }

public Item(string name, string description)
{
Name = name;
Description = description;
}
}
}


It's just a simple class with a couple of public accessors.  Now lets turn our attention to the xaml file:




   1:  <Window x:Class="DMG.AnyStream.ProfileEditor.Main"


   2:      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"


   3:      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"


   4:      xmlns:tools="clr-namespace:MyNamespace;assembly=MyAssemblyName"


   5:      Title="Sample Application" Height="600" Width="800">


   6:      <Window.Resources>


   7:          <DataTemplate x:Key="NameHeader">


   8:              <StackPanel Orientation="Horizontal">


   9:                  <TextBlock Margin="10,0,0,0" Text="Name" VerticalAlignment="Center" />


  10:              </StackPanel>


  11:          </DataTemplate>


  12:          <DataTemplate x:Key="NameCell" DataType="Profile">


  13:              <StackPanel Orientation="Horizontal">


  14:                  <TextBlock>


  15:                      <TextBlock.Text>


  16:                          <Binding Path="Name" />


  17:                      </TextBlock.Text>


  18:                  </TextBlock>


  19:              </StackPanel>


  20:          </DataTemplate>


  21:          <DataTemplate x:Key="DescriptionHeader">


  22:              <StackPanel Orientation="Horizontal">


  23:                  <TextBlock Margin="10,0,0,0" Text="Description" VerticalAlignment="Center" />


  24:              </StackPanel>


  25:          </DataTemplate>


  26:          <DataTemplate x:Key="DescriptionCell" DataType="Profile">


  27:              <StackPanel Orientation="Horizontal">


  28:                  <TextBlock>


  29:                      <TextBlock.Text>


  30:                          <Binding Path="Description" />


  31:                      </TextBlock.Text>


  32:                  </TextBlock>


  33:              </StackPanel>


  34:          </DataTemplate>


  35:      </Window.Resources>


  36:      <Grid>


  37:          <ListView Margin="0,22,0,0" Name="lvItems" ItemsSource="{Binding}" 


  38:                    IsSynchronizedWithCurrentItem="True" 


  39:                    SelectionMode="Single" >


  40:              <ListView.View>


  41:                  <GridView>


  42:                      <GridViewColumn Header="Name" HeaderTemplate="{StaticResource NameHeader}" CellTemplate="{DynamicResource NameCell}" Width="200px"  />


  43:                      <GridViewColumn Header="WatchFolderPath" HeaderTemplate="{StaticResource DescriptionHeader}" CellTemplate="{DynamicResource DescriptionCell}" Width="400px" />


  44:                  </GridView>


  45:              </ListView.View>


  46:          </ListView>


  47:      </Grid>


  48:  </Window>


Take a look at line 4. If your class lives in an assembly outside of your WPF project, like mine, then you will need to add this line to declare it to the xaml.



The Windows resources section starts at line six. Here, I'm just defining some templates that will tell the ListView how to present my information.  Without these, the control will show the results from typeof() for each item.  Not good.  Inside the "NameCell" template, I'm just creating a TextBlock control.  There's nothing to stop you from inserting images, checkboxes, radio buttons, etc. Inside the TextBlock, I create a new binding object and give it the name of the public accessor that I want to bind to this column.



The actual ListView control starts down on line 37. Notice the GridView section starting at line 41.  Here is where we define our columns. All we have to do is point to the templates that we created in the Resources section.  You could define them here, but I think that this is cleaner.>



Finally, we need to bind a list to control.  I do that in the code behind for the form:



public partial class Main : Window
{
public Main()
{
List<Item> items = new List<Items>();
items.add(new Item("Item1", "Item1 Description"));
items.add(new Item("Item2", "Item2 Description"));
items.add(new Item("Item3", "Item3 Description"));

lvItems.ItemsSource = profiles;
}
}



It took me forever to figure this out, so I hope that it saves someone some headache and/or chest pains. I know what you are saying, "I only work on web apps."  I understand that this doesn't seem that important right now, but in a recent interview with Redmond Developer News, Scott Guthrie is quoted with:



"When you look at the next public preview of Silverlight that we're doing, all of those features that are core to WPF are built-in, and there's more than just the XAML in common. You can actually take your core UI code, working with controls and databinding and things like that, and use that seamlessly in the Windows app and in the Office app and in the RIA [rich Internet application] app."



How's that for cool?




Wednesday, January 02, 2008

New Year's Resolutions

Happy New Year Kiddies!  Its that time again.  Its time to make a bunch of promises to ourselves in an attempt to justify our shortcomings from the previous year.  That's right, its time to lay down some New Year's Resolutions.  Here are some of mine.  Enjoy!

  1. Gain weight - At least I'm realistic.
  2. Eat at least 2 new animals that I haven't eaten before.
  3. Watch more TV - That one's actually a job requirement.
  4. Learn 2 new programming languages.  Does Linq count?
  5. Build 2 pieces of furniture from scratch.
  6. Project 365 - Take a picture a day for the next year. I set up a Flickr account just for this.
  7. Blog more - Thanks Jeff Atwood.

What empty promises are you making yourself this year?