Andrej Tozon's blog

In the Attic

NAVIGATION - SEARCH

Silverlight TreeView: MVVM and editing [2 – Commanding]

This post is about commanding. In MVVM application context, one way to describe commanding would be to call it a ‘declarative way of connecting Actionable Elements with some Actions by the means of Commands’.

Right… First things first – what’s an ‘Actionable Element’? Actionable elements are all elements (or controls), that can respond to some action from the user by raising an appropriate event. For example: when you click on a button, it raises the Click event. By this definition, all clickable controls are actionable elements. Let’s take a look at the TextBox – is it an actionable control? Of course it is! There are many cases you want for something to happen when you press an enter key when inside the TextBox. And thinking of a ListBox – sometimes it’s its SelectionChanged event you want to respond. Now you get the idea…

So what’s an ‘Action’? Putting it in a well-known terms, it’s simply an event handler. So instead of writing this in Xaml:

<Button Click="Button_Click" />
 
and then implementing the Click event handler in the code behind:
 
private void Button_Click(object sender, RoutedEventArgs e)
{
    // Do stuff
}
 
you would write something like:
 
<Button Command="DoSomeStuff" />
 
and instead of writing the event handler in your Xaml’s code behind, you would write it there where it belongs to. With MVVM application, this place is usually the ViewModel.

And now we get to the ‘Command’. Think of it as a some kind of a delegate to your action – your one and only event handler, which will handle that one command. Many actionable elements can then be assigned this exact command to perform when acted upon.

Commanding is also one of the many things here Silverlight differ from WPF. WPF has a powerful commanding support built in the framework, while on the other hand, there is only a small trace of commanding that can be seen in Silverlight – the ICommand interface… and that’s it! Needless to say, in order to build a competent MVVM solution in Silverlight we need commanding.

One common approach to introduce commanding in Silverlight is by attached behavior. Attached behavior is a way to extend an element by attaching a ‘behavioral’ property to it - you create an attached property with custom logic and attach this property to an element, which is supported by this property.

There are several examples on how to create commanding support in Silverlight around the web, but from what I could gather, the implementation from the SLExtensions project (CodePlex) currently seems to be the most popular one. And that’s the also one going to be used in this series. In fact, the Input folder in this solution project is a copy from the one in the SLExtensions. The SLExtensions Command pattern is not exactly the same as in WPF, but it’s very close and adequate.

To get back to our case and use the new knowledge of commanding, we’ll create two commands – one for adding, the other for deleting our help topics:

public static class Commands
{
    static Commands()
    {
        AddTopic = new Command("AddTopic");
        DeleteTopic = new Command("DeleteTopic");
    }

    public static Command AddTopic { get; private set; }
    public static Command DeleteTopic { get; private set; }
}
 
then add two buttons to our page, pointing to that commands through an attach property, provided with the abovementioned Command pattern:
 
<StackPanel Orientation="Horizontal">
    <Button Content="Add Topic" input:CommandService.Command="AddTopic" />
    <Button Content="Delete Topic" input:CommandService.Command="DeleteTopic" />
</StackPanel>

The last thing we have to do  is create the command event handlers for the actual work. We’ll do that in the ViewModel because that’s where all action is. We’ll keep the logic behind both of commands very simple: AddTopic command will add a topic as the child of the first node in the tree, while DeleteTopic will remove the last child of the same node, if any children present:

private void OnAddTopicExecuted(object sender, ExecutedEventArgs e)
{
    HelpTopics[0].SubTopics.Add(new HelpTopic() { Name = "Custom Topic" });
}

private void OnDeleteTopicExecuted(object sender, ExecutedEventArgs e)
{
    if (HelpTopics[0].SubTopics.Count == 0)
    {
        return;
    }
    HelpTopics[0].SubTopics.RemoveAt(HelpTopics[0].SubTopics.Count - 1);
}

Observing a running application (source code below) shows how User Interface (the TreeView) reacts to changes in the underlying ViewModel, triggered by commands, attached to ‘actionable’ buttons. Still no code in our Page code behind, which is good…

To finish this post, I’ll show another feature of commanding: conditional invocation. You can prevent the command from being called if the criteria for command’s invocation is not met. With the current commanding implementation, we just have return a boolean, indicating whether the criteria for a command is met or not, as a response to a CanExecute event. To check on whether a topic can be deleted or not, we’d use:

private void DeleteTopic_CanExecute(object sender, CanExecuteEventArgs e)
{
    e.CanExecute = HelpTopics[0].SubTopics.Count > 0;
}

In this post I introduced commanding and show a very basic example on how it’s used in a MVVM application.

Next in the series: moving to the TreeView [finally :)]

The source code for this sample is available:

Silverlight TreeView: MVVM and editing [1]

This is the first post in a series with a simple, yet specific goal: to add editing capabilities to Silverlight Toolkit’s TreeView control and build a MVVM (Model-View-ViewModel) pattern application with it.

This introductory post will deal with really basic stuff. Nothing new and fancy, we’re just going to set up the grounds for a simple application that displays a hierarchical collection of some help topics in a TreeView.

We’ll begin with finding the suitable hierarchical structure to put in the TreeView. For the purpose of this sample, I copied some content from Silverlight SDK documentation:

Silverlight Help Topics

First, we’ll need a data generator that will create the data structure. In a real world scenario, you would call a web service to get such data, but we’ll get to that a bit later. For now, this dummy data generator will have to do:

public static class DataGenerator
{
public ObservableCollection<HelpTopic> GetHelpTopics()
{
return new ObservableCollection<HelpTopic>()
{
new HelpTopic() { Name = "Debugging, Error Handling, and Exceptions", SubTopics =
                new ObservableCollection<HelpTopic>()
{
new HelpTopic() {Name = "Debugging Overview", SubTopics =
                    new ObservableCollection<HelpTopic>()
{
new HelpTopic() {Name = "Walkthrough: Setting Up Remote Debugging on the Macintosh"}
}},
new HelpTopic() {Name = "Error Handling"},
new HelpTopic() {Name = "Exceptions", SubTopics=new ObservableCollection<HelpTopic>()
{
new HelpTopic() {Name = "Exception Class and Properties"},
new HelpTopic() {Name = "Exception Hierarchy"},
new HelpTopic() {Name = "Exception Handling"},
new HelpTopic() {Name = "Best Practices for Handling Exceptions"}
}}
}},
new HelpTopic() { Name = "Deployment and Localization", SubTopics =
                new ObservableCollection<HelpTopic>()
{
new HelpTopic() {Name = "Creating Globally Aware Applications"},
new HelpTopic() {Name = "Localizing Silverlight Applications"}
}},
new HelpTopic() { Name = "Performance", SubTopics = new ObservableCollection<HelpTopic>()
{
new HelpTopic() {Name = "Performance Tips"},
new HelpTopic() {Name = "How To: Use a Background Worker"},
new HelpTopic() {Name = "Threading", SubTopics = new ObservableCollection<HelpTopic>()
{
new HelpTopic() {Name = "Managed Threading Overview"},
new HelpTopic() {Name = "Best Practices for Managed Threading"},
new HelpTopic() {Name = "Threading Objects and Features"}
}},
}}
};
}
}

Looks ugly, but there is really just one entity class involved – here is the HelpTopics class:

public class HelpTopic
{
public string Name { get; set; }
public ObservableCollection<HelpTopic> SubTopics { get; set; }

public HelpTopic()
{
}
}

The name property will hold the text to be displayed in a tree, and SubTopics is a collection of child items. ObservableCollection plays a significant role in MVVM applications because of its ability to inform potential listeners that the collection has changed in some way (item was added, changed, or list was cleared, etc.). With MVVM, one potential listener is the User Interface (visual elements in your application), which can react to any changes, made in data which it’s bound to.
The HelpTopic class currently doesn’t hold any unique Id field. I intentionally left that out for the moment; it will be added when needed.

OK, we have our Model. What we need next is the ViewModel. A ViewModel is a bridge between the View and the Model and acts like a Model to the View. Hence the name :)

Since it’s going to serve the main page, we’ll call it – the PageViewModel:

public class PageViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

private ObservableCollection<HelpTopic> helpTopics;

public ObservableCollection<HelpTopic> HelpTopics
{
get { return helpTopics; }
private set
{
if (helpTopics == value)
{
return;
}
helpTopics = value;
OnPropertyChanged("HelpTopics");
}
}

public PageViewModel()
{
HelpTopics = DataGenerator.GetHelpTopics();
}

protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{

handler.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

The ViewModel only has one property [HelpTopics] because that’s currently the only one we need. Notice its private setter – we’re allowing setting this property from within the ViewModel only. Also, until we implement a better method to retrieve our data, we’re initializing the HelpTopics data collection directly in ViewModel’s constructor.

The ViewModel implements the INotifyPropertyChanged interface to notify its listeners when one of its properties has changed. Similar to what ObservableCollection does, but this one’s for a single class.

To finish this, all we have left is to compose a View. We’ll populate it with a TreeView control, set it to up to display our topics and create an instance of our PageViewModel for the DataContext:

<Grid x:Name="LayoutRoot">
    <Grid.DataContext>
        <local:PageViewModel />
    </Grid.DataContext>
    <slt:TreeView VerticalAlignment="Stretch" Margin="20" Width="300" ItemsSource="{Binding HelpTopics}">
        <slt:TreeView.ItemTemplate>
            <slt:HierarchicalDataTemplate ItemsSource="{Binding SubTopics}">
                <TextBlock Text="{Binding Name}" />
            </slt:HierarchicalDataTemplate>
        </slt:TreeView.ItemTemplate>
    </slt:TreeView>
</Grid>

The PageViewModel instance is set as a DataContext of the topmost page element (Grid), which means it will serve all page’s elements. One of its consumers is the TreeView control, which takes whatever is in its HelpTopics property for its items source. The last thing we had to do is set up a HierarchicalDataTemplate, specifying the property holding the subitems, and the visual of the tree item – a simple TextBlock with its Text property bound to the HelpTopic class’ Name property will suffice.

Help Topics TreeViewThis is what our TreeView control looks now. Far from being editable or anything yet, but except coding the dummy data generator and a class with one property, we hardly did any coding; And that’s the power of the MVVM pattern.

Next in the series: modifying the data structure.

The source code for this sample is available:

Silverlight TreeView: MVVM and editing [1]

This is the first post in a series with a simple, yet specific goal: to add editing capabilities to Silverlight Toolkit’s TreeView control and build a MVVM (Model-View-ViewModel) pattern application with it.

This introductory post will deal with really basic stuff. Nothing new and fancy, we’re just going to set up the grounds for a simple application that displays a hierarchical collection of some help topics in a TreeView.

We’ll begin with finding the suitable hierarchical structure to put in the TreeView. For the purpose of this sample, I copied some content from Silverlight SDK documentation:

Silverlight Help Topics

First, we’ll need a data generator that will create the data structure. In a real world scenario, you would call a web service to get such data, but we’ll get to that a bit later. For now, this dummy data generator will have to do:

public static class DataGenerator
{
public ObservableCollection<HelpTopic> GetHelpTopics()
{
return new ObservableCollection<HelpTopic>()
{
new HelpTopic() { Name = "Debugging, Error Handling, and Exceptions", SubTopics =
                new ObservableCollection<HelpTopic>()
{
new HelpTopic() {Name = "Debugging Overview", SubTopics =
                    new ObservableCollection<HelpTopic>()
{
new HelpTopic() {Name = "Walkthrough: Setting Up Remote Debugging on the Macintosh"}
}},
new HelpTopic() {Name = "Error Handling"},
new HelpTopic() {Name = "Exceptions", SubTopics=new ObservableCollection<HelpTopic>()
{
new HelpTopic() {Name = "Exception Class and Properties"},
new HelpTopic() {Name = "Exception Hierarchy"},
new HelpTopic() {Name = "Exception Handling"},
new HelpTopic() {Name = "Best Practices for Handling Exceptions"}
}}
}},
new HelpTopic() { Name = "Deployment and Localization", SubTopics =
                new ObservableCollection<HelpTopic>()
{
new HelpTopic() {Name = "Creating Globally Aware Applications"},
new HelpTopic() {Name = "Localizing Silverlight Applications"}
}},
new HelpTopic() { Name = "Performance", SubTopics = new ObservableCollection<HelpTopic>()
{
new HelpTopic() {Name = "Performance Tips"},
new HelpTopic() {Name = "How To: Use a Background Worker"},
new HelpTopic() {Name = "Threading", SubTopics = new ObservableCollection<HelpTopic>()
{
new HelpTopic() {Name = "Managed Threading Overview"},
new HelpTopic() {Name = "Best Practices for Managed Threading"},
new HelpTopic() {Name = "Threading Objects and Features"}
}},
}}
};
}
}

Looks ugly, but there is really just one entity class involved – here is the HelpTopics class:

public class HelpTopic
{
public string Name { get; set; }
public ObservableCollection<HelpTopic> SubTopics { get; set; }

public HelpTopic()
{
}
}

The name property will hold the text to be displayed in a tree, and SubTopics is a collection of child items. ObservableCollection plays a significant role in MVVM applications because of its ability to inform potential listeners that the collection has changed in some way (item was added, changed, or list was cleared, etc.). With MVVM, one potential listener is the User Interface (visual elements in your application), which can react to any changes, made in data which it’s bound to.
The HelpTopic class currently doesn’t hold any unique Id field. I intentionally left that out for the moment; it will be added when needed.

OK, we have our Model. What we need next is the ViewModel. A ViewModel is a bridge between the View and the Model and acts like a Model to the View. Hence the name :)

Since it’s going to serve the main page, we’ll call it – the PageViewModel:

public class PageViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

private ObservableCollection<HelpTopic> helpTopics;

public ObservableCollection<HelpTopic> HelpTopics
{
get { return helpTopics; }
private set
{
if (helpTopics == value)
{
return;
}
helpTopics = value;
OnPropertyChanged("HelpTopics");
}
}

public PageViewModel()
{
HelpTopics = DataGenerator.GetHelpTopics();
}

protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{

handler.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

The ViewModel only has one property [HelpTopics] because that’s currently the only one we need. Notice its private setter – we’re allowing setting this property from within the ViewModel only. Also, until we implement a better method to retrieve our data, we’re initializing the HelpTopics data collection directly in ViewModel’s constructor.

The ViewModel implements the INotifyPropertyChanged interface to notify its listeners when one of its properties has changed. Similar to what ObservableCollection does, but this one’s for a single class.

To finish this, all we have left is to compose a View. We’ll populate it with a TreeView control, set it to up to display our topics and create an instance of our PageViewModel for the DataContext:

<Grid x:Name="LayoutRoot">
    <Grid.DataContext>
        <local:PageViewModel />
    </Grid.DataContext>
    <slt:TreeView VerticalAlignment="Stretch" Margin="20" Width="300" ItemsSource="{Binding HelpTopics}">
        <slt:TreeView.ItemTemplate>
            <slt:HierarchicalDataTemplate ItemsSource="{Binding SubTopics}">
                <TextBlock Text="{Binding Name}" />
            </slt:HierarchicalDataTemplate>
        </slt:TreeView.ItemTemplate>
    </slt:TreeView>
</Grid>

The PageViewModel instance is set as a DataContext of the topmost page element (Grid), which means it will serve all page’s elements. One of its consumers is the TreeView control, which takes whatever is in its HelpTopics property for its items source. The last thing we had to do is set up a HierarchicalDataTemplate, specifying the property holding the subitems, and the visual of the tree item – a simple TextBlock with its Text property bound to the HelpTopic class’ Name property will suffice.

Help Topics TreeViewThis is what our TreeView control looks now. Far from being editable or anything yet, but except coding the dummy data generator and a class with one property, we hardly did any coding; And that’s the power of the MVVM pattern.

Next in the series: modifying the data structure.

The source code for this sample is available:

Decimal separators in Silverlight

I run English Windows with regional settings set to Slovenian, which means I’m also using a comma (,) for my decimal separator character, not a dot (.), which is mostly used in English-speaking countries.

Silverlight sees my configuration as:

CultureInfo.CurrentCulture: sl-SI
CultureInfo.CurrentUICulture: en-US

And with my current setup I still have to use a dot for my decimal separator. To test this, I created a business object with numeric (decimal) property and use a TwoWay-bound TextBox on it.

Typing a comma-separated value into the box
 
and tabbing out of it, gets me

whereas entering a dot-separated value

leaves me with
 

Silverlight is clearly ignoring my regional settings so what can I do to make this work?

Rather than catching keystrokes and convert dots into commas etc., one simple solution comes in a form of a value converter, which would use a CurrentCulture when converting a number between string and decimal:

public class CultureNumberConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((decimal)value).ToString(CultureInfo.CurrentCulture);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
decimal returnValue;
if (decimal.TryParse(value.ToString(), NumberStyles.Any, CultureInfo.CurrentCulture, out returnValue))
{
return returnValue;
}
return value;
}
}

 
Here’s a full solution sample:

Weight Watching

If you followed me on Twitter you’d know about my latest little “problem”. I decided not to wait another month for my New Year’s resolutions, but start losing that extra weight right away. To help me keep my score, I created a little Silverlight app, showing my progress visually, through a line chart. Since charts were introduced in recently released Silverlight Toolkit, this was a very simple task.

All I had to do was:

1. Create a SQL 2008 database to keep my weight history in. The key idea here ware daily updates…
2. Expose data as a service (WCF, what else)
3. Build a Silverlight front end, which would consume this data service and present the data using the Chart bits from Silverlight Toolkit.

After browsing through some of the enclosed samples, it all boiled down to just these few lines of Xaml:

<UserControl 
    x:Class="WeightWatch.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:WeightWatch"
    xmlns:charting="clr-namespace:Microsoft.Windows.Controls.DataVisualization.Charting;
                    assembly=Microsoft.Windows.Controls.DataVisualization"
    Width="600" Height="300">
    <UserControl.DataContext>
        <local:ViewModel />
    </UserControl.DataContext>
    <Grid x:Name="LayoutRoot">
        <charting:Chart Title="Andrej's Weight Watch" LegendTitle="Legend">
            <charting:Chart.Series>
                <charting:LineSeries
                        Title="Running Weight"
                        ItemsSource="{Binding RunningWeight}"
                        IndependentValueBinding="{Binding Date}"
                        DependentValueBinding="{Binding Weight}" />
                <charting:LineSeries
                        Title="Target Weight"
                        ItemsSource="{Binding TargetWeight}"
                        IndependentValueBinding="{Binding Date}"
                        DependentValueBinding="{Binding Weight}" />
            </charting:Chart.Series>
        </charting:Chart>
    </Grid>
</UserControl>

With the exception of the ViewModel, which is responsible of fetching the data from the service, there was absolutely no additional code required for this to work. Simplicity at its best. There’s of course much more to this than just displaying static data lines in a box; I have a long way to lose those 10+ kilos, which will give me plenty of time to update this sample with some new features.

And here's my progress:

Integrating Silverlight with Community Server 2008.5

I’m sure Telligent will fully enable Silverlight parts into future Community Server releases, but until then, a couple of tricks are needed to make Silverlight play well with CS. The following points were made with Community Server 2008.5 release.

Include Silverlight apps in posts

The common way to include Silverlight in CS posts is by using HTML iframes. CS is blocking this tag by default so you have to edit communityserver.config file and enable it. Look for the <Markup> tag and go to the <Html> section within it. Add the iframe line somewhere to that section:

<iframe src = "true" frameborder = "true" width = "true" height = "true" />

Only attributes with values set to “true” will be allowed so don’t forget to add the attributes you plan to set on an iframe.

Next, upload the Silverlight app to a web site folder. The files to upload are usually the application’s [app].html (host page), [app].xap (application) and Silverlight.js (JavaScript helper library). Make sure that the uploaded .html file is accessible through the web and the app is working.

The last step is an easy one. Insert the iframe in your post wherever you want to put your Silverlight application. You’ll most commonly do that when editing posts in Html view. I usually put another div tag around an iframe:

<div style="width:100%;height:200px">
  <iframe src="/silverlight/app.html" frameborder="0" width="100%" height="200" />
</div>

Putting Silverlight into CS master page

This one requires some more manual work, but you can use CS’s master page’s system to control where you want to include Silverlight. As I needed to have Silverlight-enabled on all pages, I picked the Master.master file. I also used a different approach for embedding Silverlight – instead of iframe, I used a new Silverlight ASP.NET control, which makes things much easier. You’ll get this control in your toolbox once you install Silverlight SDK. This approach, however, will require you to “upgrade” your web.config to target .NET Framework 3.5. You can either do this manually by copying all the missing sections and other entries into it or by opening the site with Visual Studio 2008 – Visual Studio usually prompts for this kind of upgrade when opening ASP.NET 2.0 projects. You should also add the following reference line into the pages/controls section to make Silverlight possible on every page:

<add assembly="System.Web.Silverlight" namespace="System.Web.UI.SilverlightControls" tagPrefix="asp" />

My edit of Master.master file now looks like this:

... <div id="CommonHeader"> <asp:ScriptManager ID="ScriptManager1" runat="server" /> <asp:Silverlight ID="sl" runat="server" Source="/Silverlight/banner.xap"
Height="100%" Width="100%" Windowless="true" />
<div class="Common"> ...

[inserted lines bold]

Because of the inserted Silverlight control, all existing header contents were pushed further down. To fix this, override affected elements’ CSS style. You’ll do this on the Control Panel | System Administration | Site Administration | Site Theme | Custom Styles (Advanced) page. Just enter the overrides:

#CommonHeaderTitleArea
{
    position: relative;
    top: -113px;
}
#CommonHeaderUserArea
{
    position: relative;
    top: -113px;
}

[Note: my header has its height set to default – 113px, so I had to push it (-)113px up. Change this value according to your header height.

These were just very quick (and dirty) fixes to enable Silverlight in your CS2008.5 site until Silverlight gets native support in Community Site. I’ll most likely be putting even more Silverlight into my CS so I may update this post with even more tips.

Developing for ASP.NET mobile

Visual Studio 2008 introduced a lot of new features to support new technologies, adding some cool new designers to developer’s tool belt. On the other hand, support for some technologies was simply left out, leaving a some developers very unhappy. One of those was support for SQL Server 2005 BI projects (including 2005 Reporting Services).

A (long) year after its release, I learned that there was another feature dropped in VS2008 – support for designing ASP.NET mobile web forms. This doesn’t mean you can’t develop, compile and publish ASP.NET mobile forms; it simply means they pulled out the designer and mobile forms item templates out of Visual Studio 2008. Getting item templates back is the easy part, you can get them here. For the design view support, I’m not currently aware of any plans to put it back in the future.  But really – with mobile browsers getting more powerful each day, capable of rendering rich(er) (x)html, do we still need the simplicity and extendibility of ASP.NET mobile forms? For the time being, the answer may still be yes, if you’re planning to support a wide range of mobile devices. Whatever the future, the current (un)support for ASP.NET mobile in Visual Studio works for me. It’s true that I’m unable to design mobile forms in design view, but I do that rarely even with their bigger brother - ASP.NET web forms.

ASP.NET? Mobile?

Strangely enough, I’m doing more web than client development lately. Go figure.

Speaking of webby/clienty things… Silverlight 2.0 RC0 was just made available. Downloads include Microsoft Silverlight Tools for Visual Studio 2008 SP1 and Microsoft Expression Blend 2 Service Pack 1 Preview. Note that Microsoft Expression Blend 2 SP1 is a replacement for Expression 2.5, which is no more.

Creating splash screens with Expression Designer

Did you know you can create cool looking splash screens for your WPF application right there with the Expression Designer?

Of course you did. Expression Designer provides you with all you need to create free-shaped, part-transparent, drop-shadowed graphics and I bet the the WPF splash screen support is going to be baked into the next release of Expression Blend as well.

This is a quick walk through designing a splash screen with the Expression Designer.

1. With Expression Designer open, create a new rectangle and set its Corner Radius property to about 30px (depending your rectangle’s size).

2. Set rectangle’s color to match your application theme and make it a bit transparent by setting Opacity to around 70%.

Rectangle

3. Find the Effects property section and click the Add Effect button. Choose Effects | Drop Shadow.

Add Effect

4. Decrease Softness and Offset and increase Opacity properties to make the shadow more compact. You will end up with something like this:

Drop Shadow and Transparence

5. Create a new layer and put a new rectangle on it. Make it the same size as the first one and put it on the same spot to make them both aligned exactly.

6. Set its stroke to None and fill it with a transparent gradient: First Stop Alpha: 80%, Second Stop Alpha: 0%.

7. Move gradient’s origin more to the side and make it larger.

Gradient

Your rectangle should now look just a little bit more exciting:

Light source

8. Time for some text… With the Text tool, create your application title. I’ve chosen 36 pt Arial Rounded MT Bold font with white color fill. Applying some transparency to the text will make it absorb some background color for a more glassy look. You could add some Outer Glow Effect to make it even cooler.

9. Add all other text you want to show in your splash screen. Here’s what I got so far:

Title & Text

10. If you have any graphics that could communicate to the user what your application is all about, you could use that as well. It might also be a screenshot from the actual application if you can’t find anything better. I used a screenshot of my sample Live Europe Weather Map application. Adding a bitmap to the existing Expression Design project is really easy – just select File | Import… and open your graphics - it will get added to the current layer so you will probably want to create a new layer before doing that. And don’t forget to set some transparency to that as well:

Bitmap

11. Almost done. To break out of dull symmetric rectangly shape, you can mix in some additional decorations, like I did to point out that this is a whole new version of the application [the yellow badge is from the bittbox badges collection:

 Final Splash

And this is the final result for now. We’ve got transparency, irregular shape, drop shadow… Of course, this works for a sample, but for a real-world application I would have to put some additional work into it; pay more attention to the details, colors, gradients, etc.

12. When satisfied with your work, just select all objects, select File | Export… and choose PNG as your target format. After the file is saved on your disk, all you need is incorporate it in your WPF application.

Expression Design offers a lot more effects and options that were shown in this quick walkthrough. I am particularly happy to see how easy it is to play with different effects, mixing and layering them in different combination. There is, of course, also export to different Xaml instances, which makes it even more sweet.

While writing this post, I noticed that the WPF team published a new WPF Splash Screen Item Templates for Visual Studio 2008 SP1. This gives you additional option to add a splash screen to your WPF application – a new (Splash Screen (WPF)) item will be available in your templates window when adding a new item. Selecting that will insert a default graphics to your project and set it as the splash screen. You’ll have to customize the graphics yourself though. This is a nice option, although I’d like to see some form of a wizard with some styling options, font/title selections, etc… In the next version of Visual Studio perhaps…

Live Europe Weather Map in action

As promised, here’s my Live Europe Weather Map in action. This is still just a basic example of displaying icon pushpins on a map, and because I’m using Virtual Earth ASP.NET Map Control, I don’t need to worry about how map is handled and pushpins are displayed, I only need to provide data for the pushpins.

Live Europe Weather Map 

The first version of the Weather Map from a couple of years ago used to scrape the data off a Html Page. Recently, the National Environmental Agency started publishing weather data in a more collection-friendly data formats, so I switched to these.

The current version of Live European Weather Map collects Xml files, containing weather observations for European Capitals and additional cities.

Data Collection

I decided to go with LINQ to SQL option for shaping my data entity. Some may argue that LINQ to SQL isn’t a serious technology, but for small, compact projects like this, it gives me just what I need:

1. Instead of generating my data classes manually, I can create a table in my database (SQL Express in this case) and pull my classes out of that.

2. I can create my data entity by drag and dropping a table from the data source to the LINQ to SQL Class Designer in Visual Studio 2008, and my data class would get generated automatically. Here's what I’m currently collecting for weather conditions:

image

3. I can use this class to collect the data and store in into the database, or I can simply just store the collected data into ASP.NET Cache and forget the database completely.

Of course, I could’ve done it some other way (plenty of options), but this one seemed the easiest and quickest.

Weather data collection is done in a background, with a HttpModule and a timer, set to fire the collection process every 60 minutes (configurable through web.config):

   1: public void Init(HttpApplication application)
   2: {
   3:     int interval = GetCollectIntervalSetting();
   4:  
   5:     if (timer == null &&  interval > 0)
   6:     {
   7:         timer = new Timer(new TimerCallback(BackgroundCollectionCallback), application.Context, 0, interval);
   8:     }
   9: }
  10:  
  11: private void BackgroundCollectionCallback(object sender)
  12: {
  13:     WeatherCollector.UpdateConditions();
  14: }

Using LINQ to SQL, collected data is inserted into the database:

   1: public static void UpdateConditions()
   2: {
   3:     List<WeatherCondition> items = Collect();
   4:  
   5:     WeatherDataContext context = new WeatherDataContext();
   6:     context.ExecuteCommand("delete dbo.WeatherCondition");
   7:     context.WeatherConditions.InsertAllOnSubmit(items);
   8:     context.SubmitChanges();
   9: }

… and later read from it:

   1: public static WeatherCondition[] Read()
   2: {
   3:     WeatherDataContext context = new WeatherDataContext();
   4:     var conditions = from item in context.WeatherConditions
   5:                      select item;
   6:     return conditions.ToArray();
   7: }

… just to finally get shown on the map:

   1: protected void Page_Load(object sender, EventArgs e)
   2: {
   3:     if (IsPostBack)
   4:     {
   5:         return;
   6:     }
   7:  
   8:     AddWeatherPins();
   9: }
  10:  
  11: private void AddWeatherPins()
  12: {
  13:     WeatherCondition[] conditions = WeatherCollector.Read();
  14:  
  15:     for (int i = 0; i < conditions.Length; i++)
  16:     {
  17:         WeatherCondition condition = conditions[i];
  18:         if (condition.ConditionIcon == null || condition.ConditionIcon.Length == 0)
  19:         {
  20:             continue;
  21:         }
  22:  
  23:         AddPin(condition);
  24:     };
  25: }
  26:  
  27: private void AddPin(WeatherCondition condition)
  28: {
  29:     StringBuilder sb = new StringBuilder();
  30:     sb.AppendFormat("<p><b>{0} {1}</b>, {2}", condition.Temperature, condition.TemperatureUnit, condition.Condition);
  31:     if (condition.Weather.Length > 0)
  32:     {
  33:         sb.AppendFormat(", {0}", condition.Weather);
  34:     }
  35:     sb.Append("<br />");
  36:     if (condition.WindStrength.HasValue)
  37:     {
  38:         sb.AppendFormat("Wind: {0}, {1} {2}<br />", condition.WindDirection, condition.WindStrength, condition.WindStrengthUnit);
  39:     }
  40:     if (condition.Humidity.HasValue)
  41:     {
  42:         sb.AppendFormat("Humidity: {0} {1}<br />", condition.Humidity, condition.HumidityUnit);
  43:     }
  44:     if (condition.Visibility.HasValue)
  45:     {
  46:         sb.AppendFormat("Visibility: {0} {1}<br />", condition.Visibility, condition.VisibilityUnit);
  47:     }
  48:     if (condition.Pressure.HasValue)
  49:     {
  50:         sb.AppendFormat("Pressure: {0} {1} {2}<br />", condition.Pressure, condition.PressureUnit, condition.PressureText);
  51:     }
  52:     sb.AppendFormat("<br />Updated: {0}</p>", condition.UpdatedTime);
  53:  
  54:     Shape pin = new Shape(ShapeType.Pushpin, new LatLongWithAltitude((double)condition.Latitude, (double)condition.Longitude));
  55:     pin.Title = string.Format("{0}, {1}", condition.City, condition.CountryCode);
  56:     pin.CustomIcon = string.Format("images/{0}.png", condition.ConditionIcon);
  57:     pin.Description = sb.ToString();
  58:     map.AddShape(pin);
  59: }

Note that a large portion of the code is spent for describing pushpin’s popup content.

Again, this is just a drag’n’dropped Virtual Earth Map Control put to work here, without any specific client or server-side events. Looking forward to explore those in the future.