WPF

You probably already noticed that Microsoft has enabled access to the source code of parts of the .NET Framework 3.5. Here is the announcement of availability in case you missed it. And there are detailed instructions on how to enable this as well.

This morning I started stepping into the Windows Presentation Foundation. Before I knew it I was deep down into the internals of dependency properties and the Dispatcher object. The dispatcher has a nice old-fashioned message pump. I stepped into the dispatch of a message call onto a non-UI thread. Even though I already knew this, it is still startling to see that this translates into old-fashioned User32 Windows messages being send.

What really surprised me was to see a bit of VB code in a file that is called ExceptionFilterHelper.vb. According to the comment this file was needed because C#, unlike VB, does not support exception filters. However, the filter always returns true. According to the comment in the source code it is a "dummy stub to keep compiler happy, will not be replaced".

Something weird is going on here. The debugger shows I am in WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen. The source code file shows the class MS.Internal.Threading.ExceptionWrapper.TryCatchWhen. Reflector can only find the former class. The disassembly of this class shows source code that is very different than what the MS source code server gives me.

This doesn't make much sense to me. Is the source code for this class deliberately hidden or is there some error in the source code lookup?

Since I haven't had my lawyer take a look at the license agreement that governs the source code access, I will not add a screen shot of the VB code ๐Ÿ˜‰

1 Comment

Best wishes to everyone for 2008!

In the first day of the new year, I've released version 0.9.0.0 of my Flickr Meta Synchr tool. You can always find the latest version on CodePlex.

I had been working on this new version for a while now, but didn't get around to finishing it. Improvements in this new version:

  • Added much better activity logging. The activity log can now be shown in an additional window and is persisted to disk.
  • Added the option to match pictures on title and filename. This is useful when images have been timeshifted and cannot be matched on date taken.
  • Bug fixes. Improved stability when corrupt image files are encountered. Fixed GPS roundtripping bug.
  • Should run better on 64-bit versions of Windows XP and Vista.
  • Solution is now built in Visual Studio 2008 without the need for any additional WPF extensions.

Here is a screenshot of version 0.9.0.0:

Flickr Metadata Synchr v0.9.0.0

1 Comment

After a long day and night of coding, I released version 0.8.0.0 of my Flickr Metadata Synchr tool on CodePlex this morning. I finally solved the long-standing problem I was having with the Windows Imaging Component (WIC) to update metadata. So this is the first fully-functional release of my application.

Functionality of FlickrMetadataSynchr v0.8.0.0

This is what the app does:

  • It allows you to select a set of your photos on Flickr and a folder on your hard drive with images.
  • It reads the metadata for both Flickr images and the local images. The metadata that is read is:
    • Title
    • Description
    • Author
    • Tags
    • Geo-info (GPS coordinates)
    • Date and time taken
    • Last update date and time
  • It matches images on Flickr with local images based on the date and time taken.
  • It determines on a per picture basis in what direction the metadata should by synced, i.e., which side should be updated, if any. Currently the most recently updated side wins. I am getting help from Timo Proescholdt for a better algorithm that will allow for a merge of metadata, i.e., a two-way synch.
  • It updates the metadata on Flickr and in the local images.

This is a screenshot of the app:

 

Previous posts on this tool

Workaround for WIC problems

During my holiday in France in July I received e-mail from Robert A. Wlodarczyk who works at Microsoft. He pinged me to say that he had released new sample code to update metadata using WIC. Yesterday, I tried to incorporate similar code into my application and ran into the same type of problems as before.

Because his sample was working, I wasn't ready to give up again. I finally tracked the problem down to a threading issue. WIC is throwing strange InvalidOperationException and InvalidFormatException exceptions with messages like "Cannot write to the stream" when it is called from a background thread. My app is multi-threaded so that the UI doesn't hang when it is busy syncing.

After I got confirmation from Robert that WIC indeed suffers from a threading issue, I solved the problem with a work around. I now marshal the call to the code that uses WIC to update metadata to the UI thread using the WPF Dispatcher object. This causes the app to become non-responsive for small amounts of time during the update of local metadata. But that is better than a non-fully-functional app.

Fully functional, give it a try

So all is well that ends well. After finally getting WIC to work, I could do away with the C++ code that was causing me headaches ๐Ÿ˜‰ And my app now works on Windows XP again. You just need to have the .NET Framework 3.0 installed.

If you have images on Flickr and you have been busy tagging them, give my app a spin! You can always find the latest release on CodePlex. The source code is also available under a GPL license on CodePlex.

Installing is easy. You just need to unzip the ZIP-file, which contains three files, to a folder. Start the FlickrMetadataSynchr.exe file and you are done. The app remembers the last settings.

If you find any issues, please report them using the Issue Tracker for my app on CodePlex.

The Future

Even though the app is now able to sync metadata in both Flickr images and local images, there is always room for improvement. Here are my ideas, some of which are based of suggestions by people on CodePlex:

  • Improve the synchronization to also allow two-way synchronization for a picture pair. I.e., one side doesn't have to win. For example, if the Flickr image has just the title set and the local image the description, the metadata should be merged.
  • Add UI to see the match that is made by the tool and how it proposes to sync the metadata.
  • Allow you to exclude images if the match isn't good.
  • Allow you to overrule the sync proposal and sync the metadata in a different direction (on a per property basis) .
  • Add UI to store multiple mappings between Flickr sets and local folders. Currently the app only remembers the last folder and Flickr set that was used.
  • Add click-once deployment. That way the app can automatically check for new versions and update itself.

If you have any other ideas please post them at the discussions page for my app on CodePlex.

1 Comment

Some people use hyperbole to refer to the disclosure of Silverlight and CoreCLR by Microsoft at MIX07. April 30, 2007 has been called the day that will be remembered as the day that Microsoft "rebooted the web".

This might be true in more than one way. I was just reading the Silverlight SDK and was struck by a feeling of deja-vu:

<TextBlock FontFamily="Arial" Width="400" Text="Sample text formatting runs">
  <LineBreak/> 
  <Run Foreground="Maroon" FontFamily="Courier New" FontSize="24">Courier New 24</Run>
  <LineBreak/>
  <Run Foreground="Teal" FontFamily="Times New Roman" FontSize="18" FontStyle="Italic">Times New Roman Italic 18</Run>
  <LineBreak/>
  <Run Foreground="SteelBlue" FontFamily="Verdana" FontSize="14" FontWeight="Bold">Verdana Bold 14</Run>
</TextBlock>

Doesn't it feel like FONT tags all over again to you too?

This is not revolutionizing the web, this is indeed rebooting the web. Just after text on the web has been semantically liberated from FONT and TABLE tags by judicious use of CSS, we are going back to the future...

PS: Although there is extremely tight coupling between text and layout in this piece of XAML, it is still a much better situation than text locked up in .swf files. At least it is indexable by search engines. Hopefully, Microsoft is just going after the Flash market and doesn't lure us into putting all text inside Silverlight controls leaving the (X)HTML page as just an otherwise empty shell around such controls.

PS2: Here is another commentary by someone who sees some downsides to this new "rich" web as well.

WPF comes with great support for animation using XAML without needing to code this in for example C#. With Silverlight (fka "WPF/E") you can also do animations from XAML.

If you want to perform custom animations in code that you can't do using XAML, you need timers. In the full blown WPF you have several options, e.g., System.Threading.Timer, System.Timers.Timer and System.Windows.Forms.Timer.

You normally provide a callback that gets called when the timer elapses from a background thread. Properties on WPF objects can only be set from the foreground thread, so you have to queue a call on the UI thread to perform the actual animation. You can do that by calling the Invoke or BeginInvoke method on the System.Windows.Threading.Dispatcher class. You can access the correct Dispatcher instance to use through the Dispatcher property on the UI element (*).

Another option in WPF is to use the Rendering event of a CompositionTarget instance. In that case you get called when WPF is ready to render a frame. The frame rate depends on CPU speed, GPU performance, graphics complexity and other factors, so it fluctuates. This means that the interval after which you get called also fluctuates. However this is great for some scenarios.

In the current Silverlight 1.1 alpha your options are more limited. The CoreCLR libraries do have a System.Threading.Timer, but there is no Dispatcher class to delegate work to the UI thread. So it is useless for doing custom animation. In the source of the Monotone sample by Lutz Roeder I found there is an HtmlTimer class in Silverlight 1.1. This class is undocumented and marked obsolete. Visual Studio shows a warning after compilation:

'System.Windows.Browser.HtmlTimer' is obsolete: 'This is not a high resolution timer and is not suitable for short-interval animations. A new timer type will be available in a future release.

Lutz shows how to use an HtmlTimer in his sample. HtmlTimer has a Tick event. Any event handler that you wire-up to that event gets called from the UI thread. So that solves the problem for the time being.

When I tried to Google for more info on HtmlTimer, all I found was this blog post by Mike Taulty which mentions this class in passing.

(*) In fact any .NET class that derives from DispatcherObject has a Dispatcher property.

1 Comment

If you haven't heard the news yet, you must be living under a rock ๐Ÿ˜‰ There is a new CLR in town. Silverlight (fka "WPF/E") 1.1 comes with its own CLR. And the best news is that it runs both on the Mac and the PC.

Go check it out at silverlight.net.

One of the greatest achievements is that the download is a mere 4 MB. If you have a reasonably fast Internet connection you can download and install it in under a minute. Try that with .NET 3.0! That will take at least an order of magnitude longer to install.

Before the announcment at MIX07, I wasn't sure if Microsoft would be able to pull this off. They have certainly gone beyond my expectations.

This is what the Silverlight directory looks like after the install:

 

It shows you this CLR is completely separate from the standard CLR 2.0 runtime and has no dependency on it. This CLR has 2.1.x.x as version number. It has no Global Assembly Cache (GAC). You can see that support for dynamic languages like Python and JScript is included. Support for Ruby is in the works.

Go listen to the Channel 9 interview with Scott Guthrie if you want to know how Microsoft succeeded in trimming down the CLR 2.0 and the Base Class Libraries to this size.

The Silverlight .NET assemblies have the same format as standard .NET assemblies, so you can view them using Reflector. The type system is the same, so Silverlight supports generics. It will also support C# 3.0, VB 9.0 and LINQ.

These are exciting times for the .NET world. The reach of .NET has been substantially increased. Not just because the few percent of Mac users can run .NET applications now, but because it is such an easy deployment for Firefox users on the PC. And soon for Opera users as well.

1 Comment

Microsoft has announced that the little cross-platform, cross-browser cousin of Windows Presentation Foundation will be called Silverlight. This technology which was first announced at PDC05 was codenamed "WPF/E".


Tim Sneath has the best list so far of the features and power of this "Flash killer" technology. Microsoft doesn't ever call Silverlight a Flash killer, but the overlap in feature set is so large, that it cannot be viewed as anything other than a direct Flash competitor.


However, I do believe that Silverlight leapfrogs Flash in a couple of ways. The programmability and ease of use is better than Flash. You can build Silverlight sites using just Notepad if you want. The direct integration of the Silverlight DOM (Document Object Model) with JavaScript in the browser and the ability to create Silverlight UI elements on the fly with the createFromXaml method is a killer feature.


Tim Sneath mentions a secret number 10 feature on his list:



"Ah... #10. I can't reveal this yet - there's a big surprise up our collective corporate sleeve that will be announced at MIX. I hate to hold back on you, but anticipation is part of the pleasure, as my mother used to tell me as a child when I was waiting impatiently for Christmas to come!"


Could this be the .NET programmability that was previously speculated about? Soma spills some more details in his announcement:



"As I mentioned, this Silverlight announcement at NAB is only part of the story, the rest will be unveiled at MIX including details about how Silverlight is a core component of Microsoftโ€™s broader .NET platform."


I commented previously on Robert McLaws' blog that I didn't think that Microsoft wasn't going to release a lightweight crossplatform CLR for Silverlight programmability. But I also speculated that Microsoft was working on a bigger crossplatform CLR based on the .NET Compact Framework.


What I am pretty sure about, is that Microsoft will announce ASP.NET controls that will allow you to very easily integrate Silverlight on your web pages and to expose dynamic data as XAML to Silverlight controls. I.e., AJAX on steroids UI-wise.


Adding ASP.NET to the mix shows that there is no direct need for a CLR on the client in order to enable C# or VB.NET programmability: coding in C#, compiling to IL and converting that IL to JavaScript on the fly! Prototype efforts by Nikhil Kothari with Script# show that this is quite possible. Check out Nikhil's example.

Microsoft has some great news today: the new Expression Web (already RTM) and Expression Blend (RTM later in Q2 2007) tools will be included in the MSDN Premium Subscription. Soma announced this on his blog. This is the result from strong feedback from the developer community.

Although I am not a graphical designer, I have to come to appreciate both tools.

Expression Blend goes beyond what you can accomplish with "Cider". "Cider" is the codename for the WPF design surface that will be included in Visual Studio "Orcas". I used Blend to design the UI for my Flickr Metadata Synchr. And we have used it at LogicaCMG for a WPF showcase application.

Expression Web has a much richer HTML/CSS editor than the one in Visual Studio 2005. VS "Orcas" will come with a new HTML/CSS editor based on the same codebase. This will lessen the need for a separate tool for web developers, but "Orcas" will not RTM before the end of this year. I am still working on getting a more graphically inclined colleague to give up on Dreamweaver and switch to Expression Web ๐Ÿ˜‰

On a WPF app we had the need for the application to remember its window position and state (maximized, minimized) across restarts. A short journey on the Internet led me to an interesting article by TimK on CodeProject on how to do this.


As you may know, Windows Presentation Foundation makes heavy use of XAML. As it turns out XAML also allows you to mix-in behavior with your classes without using code. That is a productive way of reusing behavior. Behind the screens the mix-in class uses WPF magic as DependencyProperties to wire things up.


The article contains a WindowSettings class that stores and restores the window position and state. I fixed one bug in this WindowSettings class from TimK. Without the fix an app would restore maximized on the wrong display if it was maximized on a secondary display.


You can find the C# code for our WindowSettings class attached to this post. For your reading convenience I have also copied the code below.


To use it in your WPF window defined in XAML, do something like:

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="LogicaCMG.Client.MainWindow"
Title="Test Window" Height="700" Width="880"
xmlns:settings="clr-namespace:LogicaCMG.Settings"
settings:WindowSettings.Save="True"
>

Code of the WindowSettings class:

using System;
using System.Diagnostics;
using System.Globalization;
using System.ComponentModel;
using System.Configuration;
using System.Windows;
using System.Windows.Markup;

namespace LogicaCMG.Settings
{
/// <summary>
/// Persists a Window's Size, Location and WindowState to UserScopeSettings
/// </summary>
public class WindowSettings
{
#region WindowApplicationSettings Helper Class
public class WindowApplicationSettings : ApplicationSettingsBase
{
private WindowSettings windowSettings;

public WindowApplicationSettings(WindowSettings windowSettings)
: base(windowSettings.window.PersistId.ToString())
{
this.windowSettings = windowSettings;
}

[UserScopedSetting]
public Rect Location
{
get
{
if (this["Location"] != null)
{
return ((Rect)this["Location"]);
}
return Rect.Empty;
}
set
{
this["Location"] = value;
}
}

[UserScopedSetting]
public WindowState WindowState
{
get
{
if (this["WindowState"] != null)
{
return (WindowState)this["WindowState"];
}
return WindowState.Normal;
}
set
{
this["WindowState"] = value;
}
}

}
#endregion

#region Constructor
private Window window = null;

public WindowSettings(Window window)
{
this.window = window;
}

#endregion

#region Attached "Save" Property Implementation
/// <summary>
/// Register the "Save" attached property and the "OnSaveInvalidated" callback
/// </summary>
public static readonly DependencyProperty SaveProperty
= DependencyProperty.RegisterAttached("Save", typeof(bool), typeof(WindowSettings),
new FrameworkPropertyMetadata(new PropertyChangedCallback(OnSaveInvalidated)));

public static void SetSave(DependencyObject dependencyObject, bool enabled)
{
dependencyObject.SetValue(SaveProperty, enabled);
}

/// <summary>
/// Called when Save is changed on an object.
/// </summary>
private static void OnSaveInvalidated(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
Window window = dependencyObject as Window;
if (window != null)
{
if ((bool)e.NewValue)
{
WindowSettings settings = new WindowSettings(window);
settings.Attach();
}
}
}

#endregion

#region Protected Methods
/// <summary>
/// Load the Window Size Location and State from the settings object
/// </summary>
protected virtual void LoadWindowState()
{
this.Settings.Reload();
if (this.Settings.Location != Rect.Empty)
{
this.window.Left = this.Settings.Location.Left;
this.window.Top = this.Settings.Location.Top;
this.window.Width = this.Settings.Location.Width;
this.window.Height = this.Settings.Location.Height;
}

if (this.Settings.WindowState != WindowState.Maximized)
{
this.window.WindowState = this.Settings.WindowState;
}
}

/// <summary>
/// Save the Window Size, Location and State to the settings object
/// </summary>
protected virtual void SaveWindowState()
{
this.Settings.WindowState = this.window.WindowState;
this.Settings.Location = this.window.RestoreBounds;
this.Settings.Save();
}
#endregion

#region Private Methods

private void Attach()
{
if (this.window != null)
{
this.window.Closing += new CancelEventHandler(window_Closing);
this.window.Initialized += new EventHandler(window_Initialized);
this.window.Loaded += new RoutedEventHandler(window_Loaded);
}
}

private void window_Loaded(object sender, RoutedEventArgs e)
{
if (this.Settings.WindowState == WindowState.Maximized)
{
this.window.WindowState = this.Settings.WindowState;
}
}

private void window_Initialized(object sender, EventArgs e)
{
LoadWindowState();
}

private void window_Closing(object sender, CancelEventArgs e)
{
SaveWindowState();
}
#endregion

#region Settings Property Implementation
private WindowApplicationSettings windowApplicationSettings = null;

protected virtual WindowApplicationSettings CreateWindowApplicationSettingsInstance()
{
return new WindowApplicationSettings(this);
}

[Browsable(false)]
public WindowApplicationSettings Settings
{
get
{
if (windowApplicationSettings == null)
{
this.windowApplicationSettings = CreateWindowApplicationSettingsInstance();
}
return this.windowApplicationSettings;
}
}
#endregion
}
}

1 Comment

Bruce Eckel has an interesting post on hybridizing Java with Flash. He notices the trend in the Java world to replace Java-based GUI frameworks (AWT, Swing, etc.) for Java apps by Flash.

Incidently, I came across one such app yesterday evening when I installed PowerSnap. The UI indeed was somewhat snappy. This application claims it can keep your locally stored photographs in sync with those posted on Flickr.

Of course, the major benefit of using Flash over UI technologies as WPF is reach. WPF only runs on a subset of the Windows platforms. PowerSnap is working on a Mac version which should be relatively easy because Java and Flash are available on the Mac.

WPF/E is nice and will be cross-platform but I think it will be confined to the browser in v1. Currently the WPF/E engine can only be scripted using JavaScript.

Maybe in future versions it can be used for the GUI layer of a standalone cross-platform .NET application. Microsoft is quietly working on versions of the CLR that will run on other platforms so that WPF/E can be "scripted" using C#. The work done by the .NET Compact Framework team already proves that this is possible. This CLR runs on devices like SmartPhones, PDAs and the Xbox 360.