Andrej Tozon's blog

In the Attic

NAVIGATION - SEARCH

Until we meet again...

You left so sudden
I couldn't even say goodbye.
You've lived a hard life,
but did everything
to make mine easier.
Your faith, courage and love
will continue to live on
through your words and wishes:
"Love one another".

I'll miss you, Mom!

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…

Splash Screen in WPF 3.5 SP1

Besides improving application startup time, .NET Framework 3.5 SP1 also allows developers to add a splash screen to WPF applications. The splash screen is shown using native code, even before WPF application starts to load. In reality this means the splash screen would show immediately when application is started, and fade away a couple of seconds later, when application is fully loaded and main screen displayed.

WPF Splash screen is just and nothing more than a plain bitmap image. Common formats are supported, and if you use a PNG format with a specified alpha channel, transparent areas will be shown accordingly. Just remember to keep it small. Choosing a couple of megabytes large bitmap for your splash screen won’t reduce the loading time. Adding additional information to the image during runtime (title, version number) is also not possible; everything you want to show should be designed in advance and incorporated into a single image.

WPF splash screens can be added to an application in two ways:

Showing splash screen manually

1. Create a new PNG image, which will be your splash screen.

2. Start your Visual Studio 2008 SP1 and create a new WPF project. [make sure .NET 3.5 is specified as the target FX]

3. Choose Project | Add Existing Item… Find and select your splash screen image.

4. Open App.xaml file in design view and look in the properties window ;)

Events in VS2008 WPF designer

Yes, there’s an event panel in WPF designer! And properties/events sorting option buttons!

5. Create a Startup event handler:

   1: private void Application_Startup(object sender, StartupEventArgs e)
   2: {
   3:     SplashScreen screen = new SplashScreen("sp1splash.png");
   4:     screen.Show(true);
   5: }

6. Compile and run.

The SplashScreen constructor takes the name of the resource, which is a splash screen image. The boolean parameter in the Show() method specifies, whether the splash screen should fade out when application is fully loaded. False means you’ll have to hide the splash screen manually using the Close() method.

If you don’t like writing code, this gets even easier:

 

Showing splash screen declaratively

1. Create a new PNG image, which will be your splash screen.

2. Start your Visual Studio 2008 SP1 and create a new WPF project. [make sure .NET 3.5 is specified as the target FX]

3. Choose Project | Add Existing Item… Find and select your splash screen image.

4. Select the newly added image in the solution explorer and show its properties.

5. Change the Build Action to SplashScreen.

6. Compile and run.

The splash screen shows immediately upon the application startup and fades out when the main window is loaded and shown. How’s that for cool new user experience :)

 

Additional note: SplashScreen class works in WPF desktop apps only, XBAPs have their own mechanism for starting up.

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.

VSM4WPF

While next release of WPF (3.5 SP1) won't yet align with Silverlight's "Parts & States Model"  by not introducing VisualStateManager into its API, it's good to know that VSM is definitely coming to WPF. Even more, John Gossman has just released a prototype of his VisualStateManager for desktop WPF, which is compatible with Silverlight Beta 2 VSM implementation.

Before VSM is built into the core of WPF, this prototype lets us explore and play with this "new way" of controls' state transitioning in WPF applications. Sweet.

Silverlight Olympics

Want to tune into 2008 Beijing Summer Olympic Games with Silverlight?

Not in the United States, you say?

Well, tough luck ;)

NBC Olympics

This IP restriction thing is getting sillier by the day... Isn't Internet supposed to be global? What happened to World Wide Web? :)

The tide is high – new MS downloads

SQL Server 2008 RTM is out!

Microsoft Sync Framework v1.0 RTM is out!

  • Sync Services [now @ v2] is “synchronized” with Sync Framework
  • Peer 2 peer database sync support
  • Sync with device’s Database
  • SQL2008 Change Tracking supported
  • Sync process tracing

A couple of features of the above products require VS2008/.NET 3.5 SP1, which means VS2008 / .NET 3.5 service pack duo should be released real soon now [by August 11th, as stated on MSDN).

Like it’s not hot enough already… turning my air-con down to keep my boxes cool and running…

[Update] SQL Server Compact 3.5 SP1 is out!

[Update] .NET FX 3.5 SP1 is out!

  • ADO.NET Data Services
  • Entity Framework
  • ASP.NET Dynamic data

[Update] Visual Studio 2008 SP1 is out!
[Update] Need to update Silverlight Tools for VS2008 too.

Sources: here, here, here, here

Live Europe Weather Map with Windows Live Tools Map Control

A while ago I built a sample weather map using Atlas [now Microsoft Ajax] and VirtualEarthMap control, which used real-time data to display current weather conditions.

VirtualEarthMap control was steadily progressing all this time as a part of a separate SDK, until released as a new ASP.NET control with the latest Windows Live Tools for Microsoft Visual Studio release last week [July CTP, download here].

Working with the control appears to be easy. It took me about 15 minutes [including Tools’ download+setup] to port the previous version to use this new control. No RTFM, just drag and drop, set properties and copy/modify some relevant code. And still, the current implementation consumes only small part of functionality this control offers, leaving a lot of space for additional enhancements.

Here’s a screenshot of the control in action:

Europe Weather

What the application does is capture the weather data from the national Environmental Agency and display them on the map as custom pushpins, each pushpin representing a city, where the readings are being collected; hovering over each pushpin will give you more information about that city weather station’s readings.

I’m going to post a live example with some code after I give this control some more time to show me what it can really do.

Label.Target Pt.2: The return of the (not so) attached property

Following my previous example, this is another experiment with the Label.Target property.

Suppose you want to restrict user’s progression with data input on a form by disabling some crucial input fields, which input depends on some other fields on the form. There’s more than a couple of ways for doing this and the first solution that springs to mind would be doing it by employing business object data validation. But if you need a pure UI/XAML solution, this can be the alternative:

image 
[See it live – loose Xaml page ahead ]

What’s happening in the sample above – the second TextBox gets enabled only when the first TextBox is not empty. The same goes for the third box, except here’s the second box that has to have some text entered into it.

This was done with the help of data triggers:

   1: <Label Target="{Binding ElementName=firstBox}" Content="_1st:" />
   2: <TextBox Name="firstBox" Grid.Column="1" Margin="2" /> 
   3: <Label Target="{Binding ElementName=secondBox}" Content="_2nd:" Grid.Row="1" />
   4: <TextBox Name="secondBox" Grid.Column="1" Margin="2" Grid.Row="1">
   5:   <TextBox.Style>
   6:     <Style TargetType="{x:Type TextBox}">
   7:       <Style.Triggers>
   8:         <DataTrigger Binding="{Binding Path=Text.Length, ElementName=firstBox}" Value="0">
   9:           <Setter Property="IsEnabled" Value="false" />
  10:         </DataTrigger>
  11:       </Style.Triggers>
  12:     </Style>
  13:   </TextBox.Style>
  14: </TextBox>
  15: <Label Target="{Binding ElementName=thirdBox}" Content="3rd:" Grid.Row="2" />
  16: <TextBox Name="thirdBox" Grid.Column="1" Margin="2" Grid.Row="2"> 
  17:   <TextBox.Style>
  18:     <Style TargetType="{x:Type TextBox}">
  19:       <Style.Triggers>
  20:         <DataTrigger Binding="{Binding Path=Text.Length, ElementName=secondBox}" Value="0">
  21:           <Setter Property="IsEnabled" Value="false" />
  22:         </DataTrigger>
  23:       </Style.Triggers>
  24:     </Style>
  25:   </TextBox.Style>
  26: </TextBox>

There’s a lot of repetitive Xaml code above that can be put away by using a style and an attached property.

[Note: I’m going to hijack the Label.Target dependency property here just because it suits the needs for this sample - it’s not even registered as an attached property and this wouldn’t even compile in Visual Studio! In a real application you would want to produce a completely new attached property to avoid all potential troubles that may result from such (mis)use]

As mentioned in the previous post, a Label.Target property can hold a reference to another control on the page. We’re going to use the property to point to the dependency source control:

   1: <Label Target="{Binding ElementName=firstBox}" Content="_1st:" />
   2: <TextBox Name="firstBox" Grid.Column="1" Margin="2" /> 
   3: <Label Target="{Binding ElementName=secondBox}" Content="_2nd:" Grid.Row="1" />
   4: <TextBox Name="secondBox" Grid.Column="1" Margin="2" Grid.Row="1"
   5:   Label.Target="{Binding ElementName=firstBox}" />
   6: <Label Target="{Binding ElementName=thirdBox}" Content="3rd:" Grid.Row="2" />
   7: <TextBox Name="thirdBox" Grid.Column="1" Margin="2" Grid.Row="2" 
   8:   Label.Target="{Binding ElementName=secondBox}" />

The global style is applies the same principle, shown in the previous post:

   1: <Style TargetType="{x:Type TextBox}">
   2:   <Style.Triggers>
   3:     <DataTrigger Binding="{Binding Path=(Label.Target).Text.Length, RelativeSource={RelativeSource Self}}" Value="0">
   4:       <Setter Property="IsEnabled" Value="false" />
   5:     </DataTrigger>
   6:   </Style.Triggers>
   7: </Style>

The data trigger in the above style disables the target TextBox when its Length property is set to 0.

This looks good already, but something is not right… Hint: try the current example live and fill all three boxes, then clear the first one.

We need to fix this and we’ll do it by adding another data trigger, which disables the current TextBox whenever the source TextBox is disabled. Here’s slightly modified version of the style:

   1: <Style TargetType="{x:Type TextBox}">
   2:   <Style.Triggers>
   3:     <DataTrigger Binding="{Binding Path=(Label.Target).Text.Length, RelativeSource={RelativeSource Self}}" Value="0">
   4:       <Setter Property="IsEnabled" Value="false" />
   5:     </DataTrigger>
   6:     <DataTrigger Binding="{Binding Path=(Label.Target).IsEnabled, RelativeSource={RelativeSource Self}}" Value="false">
   7:       <Setter Property="IsEnabled" Value="false" />
   8:     </DataTrigger>
   9:   </Style.Triggers>
  10: </Style>
Well, that’s all, really… A simple example to show the power of WPF data binding through the attached properties. [A post on creating a proper attached property for this sample will follow as I move away from Xaml-only examples]

And this is the final result code for this post [See it in action – loose Xaml file]