Oct 26, 2008

Code Camp Slide Deck and Sample Code

Thanks to everyone who came out to our Code Camp presentation (and sweated through the lack of A/C with us)

You can get a copy of our slide deck and our sample application here (The slide deck is added as a solution item)

(It requires VS 2008)

If you didn't get a chance to see the presentation we have, at least, one more date scheduled. November 12th at the San Diego .NET User Group Architecture SIG.

Oct 22, 2008

Photo Stackr (Silverlight goodness)

Update: I updated the code to work with Silverlight 2 RTW. 

So with the release of the Silverlight 2 beta bits I finally decided to see what all the talk was about. I suppose I would consider myself an ASP.NET guy by trade. Although I have been building WPF applications for the past year or so and generally I am enjoying NOT building web applications. However, I can't hide the fact that I spent the last seven odd years building mostly ASP.NET applications.

So when I first heard of Silverlight and heard it was in the same vain as Flash I was skeptical to say the least. I would say I was somewhere closer to outright disgust. I spend so much time focusing on a lightweight client that offloads it's work to a controlled and decidedly beefier web server. There is no way I want to push a plug-in to a client and THEN pay the price of shoving all the assest's down the pipe and hoping their machine can handle it. but alas, I will give it a fair shake. I do like WPF after all.

So with that said I wanted to see what the development experience is like and what kind of things I could do with the WPF skills I had amassed. 

Cue PhotoStackr (note the gratuitous web 2.0 spelling)

One of the things I really like with WPF, and the main thing that makes WPF so compelling to me, is that it gives you the ability to focus on user interaction and user experience and less on implementation details. This allows you to build incredible applications with minimal effort (compared to building the equivalent in WinForms). So before I show the gory details of my Silverlight application I will say that I was trying to build an application that models a known collection of data (in this case a set of photos from the flickr website) in a new / interesting way.

To that end Silverlight, really XAML in general, gives you the tools to visual your data quickly. For the photo stackr application I wanted to give a interesting way to view and organize multiple search results on a single page.

What I like about Silverlight is it changes the development paradigm on the web. With the plug-in architecture you have a stateful environment to develop to. You can write fully managed code to do things previously done on the client in JavaScript (like drag and drop)

The basic design idea of PhotoStackr is to have a "Photo Table", which is the main canvas of the application. On the table you will have multiple "Photo Stacks." These stacks are the result of searching the Flickr web service for a specified tag. The application will give you the ability to "un-stack" your search results so you can view all results at once. You can then zoom in on any one of the results to view the photo in more detail.

There is a link at the bottom of this post where you can get the entire project to view the code in more detail so I will just focus on the main points.

The main canvas is pretty simple I put a text block to show the title in the top left and then two custom controls, one for the search box and one for the about window. I am toggling the visibility of these controls on the button click event of the respective buttons. This brings me to my first annoyance with Silverlight. The current build doesn't support triggers. Triggers are fundamental (IMHO) to WPF. Since I am approaching Silverlight with a WPF background the lack of triggers is painfully obvious. However, Sivlerlight is still in beta so some features just aren't there. I don't know if there is a plan to support triggers in Silverlight. Personally, I think they have to be supported if they want Silverlight to follow the "Do it in markup, not in code" mantra.

<Canvas Background="Black" x:Name="Table" Loaded="Table_Loaded" SizeChanged="Table_SizeChanged" >
<TextBlock x:Name="Title"Text="Photo Stackr"FontSize="16" Canvas.Left="100" Canvas.Top="50" Opacity=".4"/>
<Button x:Name="AddButton"Click="AddButton_Click" Template="{StaticResource AddStackButtonTemplate}" Canvas.Left="100"Canvas.Top="650"/>
<Button x:Name="AboutButton"Click="AboutButton_Click" Template="{StaticResource AboutButtonTemplate}" Canvas.Left="125" Canvas.Top="650"/>
<local:MessageControl x:Name="About"Canvas.Left="250"Visibility="Collapsed"/> <local:SearchPopup x:Name="SearchPopup"Canvas.Left="100"Visibility="Collapsed" />
</Canvas>  


I like the control architecture that Silverlight drives you towards. I have built the SearchPopup and the MessageControl as separate UserControls in it's own XAML file. This is nothing revolutionary, you could do this in ASP.NET with custom controls, but with the stateful environment it makes managing multiple controls much easier. The controls are more aware of the application domain data and don't need state management code to work with the rest of the application. This gives you a development experience much closer to desktop development. This is a big plus to me.



When the user enters a search tag and clicks the search button I create a PolaroidStack control. This control is a canvas that has the logic to manage multiple Polaroid controls and perform the stack and un-stack behaviors. This brings me to the first programming feature that I really like about Silverlight. On the PolaroidStack control I added a static dependency property called SelectedTag





public static readonly DependencyProperty SelectedTagProperty = DependencyProperty.Register("SelectedTag", typeof(string), typeof(UserControl),OnSelectedTagChanged); 


Dependency properties come from WPF and are a key component to control development. Since I have a dependency property on the PolaroidStack all I have to do in code is set the property and the change handler code in the stack control will take care of the rest. 





PolaroidStack s = new PolaroidStack();
s.SetValue(PolaroidStack.SelectedTagProperty, SearchPhrase.Text);



Change handler for the PolaroidStack.SelectedTag property:



private static void OnSelectedTagChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//Reload the Polaroid Stack
((PolaroidStack)d).LoadStack(e.NewValue.ToString());
}




The nice thing about the DependencyProperty is that it can also be set in markup. If I created the PolaroidStack in markup I could set the SelectedTag property in the markup as well which would cause the stack load itself when the control is loaded (and this is exactly what I did to test the LoadStack functionality)



In the LoadStack method I make a call the the Flickr Rest based Webservice passing the tag that the user passed in as the search term. The only thing to note here is that I am processing the result of the web service using LinqToXml which makes processing the XML document leaps and bounds easier then before.  



XDocument doc = XDocument.Parse(e.Result);
var photos = from results in doc.Descendants("photo")
select new
{
id = results.Attribute("id").Value.ToString(),
farm = results.Attribute("farm").Value.ToString(),
server = results.Attribute("server").Value.ToString(),
secret = results.Attribute("secret").Value.ToString()
};


This snippet of code basically creates a dynamic collection and I am defining the members of the objects in the collection by selecting the attributes from the XML document. So I have a collection of Photos, the items in the collection are of type Photo. The Photo type (which is a dynamic type created by LINQ when I call select new) has string members id,farm,server, and secret. And this ends my LINQToXML lesson :), LinqToXML is really cool, for more info check here



After processing the web service response into a collection of Photo objects, I iterate the collection and build a new Polaroid control. The Polaroid control is a custom user control composed of an Image control, a button to control the zoom, and a border to give the look and feel of a Polaroid.





<Canvas Height="110" Width="91" Background="#FFFFFFFF" x:Name="PolariodCanvas"> 
<Button x:Name="Zoomer" Canvas.Left="70" Canvas.Top="95.666" Click="Button_Click" />
<Image x:Name="imageControl" Height="75" Width="75" Stretch="Fill" Canvas.Top="8" Canvas.Left="8"/>
<Border Height="75.75" Width="76.006" Canvas.Left="8" Canvas.Top="8" BorderBrush="#FF000000" BorderThickness="1,1,1,1"/>
</Canvas>   


I am also creating a rotate transform in code to randomly set the angle of the Polaroid control to give it the messy look when stacked on top of each other. Again, the control development approach works nicely here because I can keep the logic to zoom the Polaroid in the Polaroid control.



The last thing to point out here is how I implemented drag and drop logic. I wanted to give the ability to drag and drop the PolaroidStack control so I hooked into the mouse button events of the Polaroid control. The actual drag and drop code is nothing new but the ability to do it all in managed code is the big difference. Previously this type of thing would have to be done in javascript. With Silverlight you can do it all in managed C# code 



private void PolariodStack_MouseMove(object sender, MouseEventArgs e) 
{
// only execute this code when the user has started dragging
if (startDrag)
{
Point movePos = e.GetPosition(null);
double currentX = double.Parse(this.GetValue (Canvas.LeftProperty).ToString()) + (movePos.X - beginPos.X);
double currentY = double.Parse(this.GetValue(Canvas.TopProperty).ToString()) + (movePos.Y - beginPos.Y);

this.SetValue(Canvas.LeftProperty, currentX);
this.SetValue(Canvas.TopProperty, currentY);
beginPos = movePos;
}
}  


<Borat> Very Nice </Borat>  



You can get the code for this project here. NOTE: you will have to sign up for a Flickr account and get your own API key to get this to work. I purposely forced a compile error to show you were to enter your API key.



So in the end, I like what Silverlight offers so far but it isn't all the way there yet. The lack of support for DataTemplates and Triggers  are glaring issues. I am also still not sold on the plug-in approach. Solving the satefulness issue is huge and I think that is the overriding win with the plug-in approach but I am still concerned with pushing that much on to the client machine. The temptation to abuse the technology is high and pushing really intensive applications down the wire to the client can lead to bloated applications and serious support issues. 



To see the application in action visit our Silverlight page silverlight.interknowlogy.com  



Tell me what you think

Oct 20, 2008

Sharing Mock Data for Unit Tests and Blend

I have been diving in to Inversion of Control and specifically the Dependency Injection / Inversion (DI) pattern recently and I have been trying to find legitimate ways to fit the pattern into my workflow. First off I will say I really like the DI pattern and it has plenty benefits which I will try to discuss in a series of blog posts in the future (or if you want to hear about it in person come to my presentation at Code Camp)

What I have been to trying to work out this week is how can I provide a seamless way for developers and designers to share mock data between unit tests and Blend. The prerequisite for this approach to make sense is that you are doing unit tests during your development process. Assuming that is the case then I think the following solution could work out nicely.

If you are following the DI pattern then you will know that it is easy to swap out different concrete types for a given interface. The DI patterns focuses on the idea of programming against interfaces. That way, your code is decoupled from the details of the implementing type. This allows you to easily swap out the real version of your data classes for Mock versions. This gives you a nice way to cleanly unit test your code without being dependent on any sort of external environment (SQL DB, Web Services, etc..)

So if you are following this pattern and creating mock versions of your data classes why not share those with Blend designers? One of the complaints I hear often from Blend designers is that they struggle to create data visualizations when they don't have any data (duh). Using mock data classes is a great way to provide sample data for designers to use in Blend so they can see what the screen will look like when it is connected to data. If you are already creating the mocks for unit test purposes then sharing with Blend isn't any much more work on your part.

If you separate your Interface definitions and your Mock Data classes in to separate .NET projects like this

  

Then you have a way for your Unit Tests and your Main application to leverage the Mock Data. A unit test that uses the the MockPerson type might look something like this

var person = new MockPerson();Assert.IsNotNull(person); 
Assert.AreEqual(person.GetFirstName(), "MockFirstName");
Assert.AreEqual(person.GetLastName(), "MockLastName");
Assert.AreEqual(person.GetFullName(), "MockFirstName MockLastName");


Where the implementation of the MockPerson class looks like this



public class MockPerson : IPerson
{
public string GetFirstName() { return "MockFirstName"; }
public string GetLastName() { return "MockLastName"; }
public string GetFullName() { return string.Format("{0} {1}", GetFirstName(), GetLastName()); }
}


Notice how MockPerson implements the IPerson interface. This is key to allowing the use 
of Mock data classes. I will dive deeper
into programming against interfaces and the DI
pattern in future posts.


Now if we want to use this MockPerson class to provide sample data to a designer in Blend 
we need first understand what Blend does when constructing your XAML file. My first
thought was that Blend would call my constructor in the XAML.cs file for the XAML file
I was opening in Blend.


However I was wrong. Blend will not call your constructor but it will construct any objects 
that are specified in the XAML markup itself. This means that if you set the DataContext
attribute of your XAML file in XAML like this


<Window x:Class="IoCSample.Window1" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:IoCSample="clr-namespace:IoCSample"
Title="Window1"
Height="300"
Width="300">

<Window.DataContext>
<IoCSample:ViewModel />
</Window.DataContext>


Then you will have a piece of code that you can hook into to check and see if you are



in DesignMode. To check and see if you are in DesignMode you can use the following



code:



DependencyPropertyDescriptor descriptor = DependencyPropertyDescriptor.FromProperty(DesignerProperties.IsInDesignModeProperty, typeof(System.Windows.DependencyObject));
var isInDesignMode = (bool)descriptor.Metadata.DefaultValue;
if (isInDesignMode)
{
}


Now to actually provide MockData to Blend we want to check this IsInDesignMode property and provide Mock implementations of the data classes we need. Sticking with the example above of IPerson and MockPerson, let's say that our ViewModel class (which is specified as the data context for the XAML file we are opening in Blend) has a property of type IPerson. Defined like this



public class MockPerson : IPerson
{
public string GetFirstName()
{
return "MockFirstName";
}

public string GetLastName()
{
return "MockLastName";
}

public string GetFullName()
{
return string.Format("{0} {1}", GetFirstName(),
GetLastName());
}
}




And say we are binding to that property in our XAML like this (Remember our DataContext is set to the ViewModel class shown above so  {Binding PersonFirstName} refers to the PersonFirstName property on the ViewModel class)



<TextBlock Text="{Binding PersonFirstName}" />  


Notice the check in the ViewModel constructor above to see if we are in design mode. Now we have a place to check if we are in design mode and create a MockPerson object if we are. To do that we will modify the ViewModel constructor to look like this:



public ViewModel() 
{
DependencyPropertyDescriptor descriptor = DependencyPropertyDescriptor. FromProperty(DesignerProperties.IsInDesignModeProperty, typeof(System.Windows.DependencyObject));var isInDesignMode = (bool)descriptor.Metadata.DefaultValue;
if (isInDesignMode)
{
Person = new MockPerson();
}
}


Remember from above that the MockPerson class has some "Mock" data (hence the name) in the property getters. So a call to Person.GetFirstName(); (which is called from the Binding in the XAML file {Binding PersonFirstName})  returns "MockFirstName" .



Now when we open this file in Blend it will fire the ViewModel constructor and make the check to see if we are in DesignMode, if we are it will construct a new MockPerson object and set the ViewModel IPerson property to the MockPerson instance. This will provide MockData to the Blend designer. This is a very basic approach to this solution. In a future blog post I will describe a more detailed approach that involves a custom markup extension and ties in to an Inversion of Control container to provide a generic way of registering Mock object dependencies with your IoC container for DesignTime and UnitTest development. But for now this solution should get you started and help you provide a richer design time experience for Blend designers.

Visual Studio XAML designer annoyances

 

UPDATE: MSFT has released a patch for the XAML designer in Visual Studio 2008 SP1. This patch appears to fix some edge cases with the designer that cause it to crash VS. You can get the patch here: http://code.msdn.microsoft.com/KB958017

I pretty much abandoned the integrated XAML designer in VS long ago. It is painfully slow to load and even after waiting several minutes for it load it usually just shows the brilliant "We're sorry... our designer blows" screen. Recently a co-worker was having some problems with XAML files crashing Visual Studio. He had just installed VS 2008 SP1 and .NET 3.5 SP1. No idea what the issue was but I suggested that he try switching his XAML editor to open XAML pages in full XAML view. I realized that maybe other people don't know how to do this since the option is buried pretty deep.

 

So a quick to post to show how to do this.

In the VS IDE click Tool | Options

 

Then expand the tree for Text Editor

 

Scroll down and you should see a XAML section. Expand the XAML tree

 

 

Then click on the Miscellaneous item. Now you will see a check box that says "Always open documents in full XAML view"

 

Click OK and you are all set. Now when you open XAML files in VS they will open in full markup view. This prevents the designer from loading. This should speed up the time it takes to open XAML files. And in some cases it looks like it prevents the IDE from crashing. Interesting to note, after making this change my coworker was able to switch to design view and reload the designer and this time it did not crash Visual Studio. hmmm? Race condition maybe?

Labels: