Handling Images with the HtmlToXamlConverter

I was asked via a comment “why won’t HtmlToXamlConverter display images, for example those embedded in an RSS feed’s contents?”.

The answer is probably indicated by the comment in the HtmlToXamlConverter classes AddBlock() method :

        case "img":
// TODO: Add image processing
            AddImage(xamlParentElement, htmlElement, inheritedProperties, stylesheet, sourceContext);
break;

And the equally terse AddImage() method itself:

        private static void AddImage(XmlElement xamlParentElement, XmlElement htmlElement, 
Hashtable inheritedProperties, CssStylesheet stylesheet,
List<XmlElement> sourceContext) { // Implement images }

I’d tweaked the HtmlFromXamlConverter AddImage class as follows:

        private static void AddImage(XmlElement xamlParentElement, 
XmlElement htmlElement,
Hashtable inheritedProperties,
CssStylesheet stylesheet,
List<XmlElement> sourceContext) { // Implement images (HACK by Nigel Spencer) bool inLine = (xamlParentElement.Name == HtmlToXamlConverter.Xaml_Paragraph); XmlElement xamlUIContainerElement = null; if (inLine) xamlUIContainerElement = xamlParentElement.OwnerDocument.CreateElement(
null, "InlineUIContainer", _xamlNamespace); else xamlUIContainerElement = xamlParentElement.OwnerDocument.CreateElement(
null, "BlockUIContainer", _xamlNamespace); XmlElement xamlImageElement = xamlParentElement.OwnerDocument.CreateElement(
null, "Image", _xamlNamespace); xamlImageElement.SetAttribute("Source", htmlElement.GetAttribute("src")); xamlImageElement.SetAttribute("Stretch", "None"); xamlUIContainerElement.AppendChild(xamlImageElement); xamlParentElement.AppendChild(xamlUIContainerElement); }

Don’t expect too much from this though. If you really need to display rich HTML in a WPF app then use a Frame control. However, if like me, you’ve got some predominantly textual data stored in HTML and you want to make use of the great FlowDocument reader controls then the HtmlFromXamlConverter is a great little utility.

The source code for my test WPF harness was as  follows:

    public partial class Window1 : Window
    {
public Window1()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
FlowDocument flowDocument = new FlowDocument();
string xaml = HtmlToXamlConverter.ConvertHtmlToXaml(textBox1.Text, false);
using (MemoryStream stream = new MemoryStream((new ASCIIEncoding()).GetBytes(xaml)))
{
TextRange text = new TextRange(flowDocument.ContentStart, flowDocument.ContentEnd);
text.Load(stream, DataFormats.Xaml);
}
flowDocumentReader1.Document = flowDocument;
}
}

Some very simple HTML to test. I also tested with HTML source from a  blog post of two and it seemed OK.

<HTML>
<BODY>
<p>The <b>Markup</b> that is to be converted.</p>
<p>An inline image [<img src="http://www.microsoft.com/australia/remix08/images/bling/iamgoing_08.jpg"/>]</p>
<p>Ooh! <i>Beautiful.</i></p>
<img src="http://images.quickblogcast.com/public/visitorImages/black_createdby.gif"/>
<p>Hmm...</p>
</BODY>
</HTML>

ReMIX08 in Australia

Well I’ve booked my flight, registered and got the day off work (in that order). I am not a “web guy”. I’ll go on record as stating that I was over JavaScript and HTML back in 2000. Whilst it was kinda fun to play with for a couple of months I’m not about to go writing any serious applications with those technologies. [I’ll leave that to the hordes of happy web devs who somehow seem to enjoy it.]

Regardless I was very impressed with the content that I saw coming out of Mix08 this year. In particular being such a WPF fan I think Silverlight 2 is sounding pretty sweet. Maybe, just maybe, I’ll convert from writing enterprise client-apps and do some web front-end development? As long as you promise I don’t have to touch a scripting language or HTML right?

I'm going to REMIX. Are you?

So who else is going to ReMIX08? Anyone from Adelaide making the early morning flight over to Melbourne on 22nd May?

Oh – and a complimentary copy of Expression Studio 2 – nice!

Source Code Comments – Time for a revamp

[If you’re impatient then check out the image here to jump straight to the reason behind this post.]

When Microsoft first declared there intent to include support for comments within the C# language I was overjoyed. I was so taken with the idea that I wrote a VB6 add-in that would parse VB6 source comments prefixed by ‘/ and convert them into a HTML page which documents the class. Importantly it also provided a real-time preview window for the current method/property.

As it turned out when .NET was finally released I landed a job coding in VB.NET rather than C#. There were a couple of freeware tools around that would allow the XML documentation files to be produced from VB.NET source code. They were OK but it really wasn’t the same as having the compiler validate comment references. Also most of the tools we tried were a little flaky and prone to crashing every now and then.

Jumping ahead a few years and I’m using C# with Visual Studio 2005 on a large scale project. On this project I was responsible for writing a lot of architecture and doing my best to make sure it was documented. We used NDoc to produce MSDN style Help via MSBuild and our continuous integration engine (CruiseControl.NET). We also had to produce a script that would correctly register the generated v2 Help file to have it integrate seamlessly with the Visual Studio documentation. Setting this up was tricky. It required us to debug and fix the latest NDoc build to properly support generics, use another third party tool to generate the required Help registration goo, write custom NDoc tags for inserting images (like class diagrams) and creating FAQ indexes etc. It would also take about an hour to run (over our 40+ project solution).

But NDoc is dead!

Yes, but as everyone knows Sandcastle lives! The first few drops of Sandcastle were really quite scary. Config files here there and everywhere, write your own scripts to produce the end result. But whilst Microsoft were concentrating hard on getting the fundamental engine right the community came to the rescue  with Sandcastle Help File Builder (SHFB). A full featured, easy to use GUI to produce Help v1, v2 and HTML documentation using the Sandcastle engine. The recent builds of Sandcastle coupled with SHFB and we’re finally back (in fact slightly ahead) of where NDoc left off. The SHFB has even been built to look and feel just like the NDoc GUI – nice!

Sandcastle - UriToThumbnailConverter 

Some HTML v1 output from Sandcastle using SHFB.

Source Comments are ugly

However, having had a chance to write a fair amount of source comments on this particular VS2005 project, one thing became obvious. Improving the quality of the externally viewed documentation (e.g. in dexplore, or HTLP Help Viewer) had a directly negative effect on the readability of the same documentation within the source files (e.g. Visual Studio).

In other words – adding more markup to the source comments made them harder to read in Visual Studio. Yet I want the both of best worlds. I want to be able to produce useful documentation integrated with MSDN but at the same time I want those comments to be easily read by the developer when they are right there in the source.

/// <summary>
/// This <see cref="IValueConverter"/> allows image paths in XAML to be efficiently converted into
/// thumbnail images which could, for example, be used to populate an <see cref="ItemsControl"/>.
/// </summary>
/// <remarks>
/// <para>
/// This converter relies on the image file referenced by the string representation of the value
/// having a thumbnail image stored as part of its metadata. This will be likely for any image that
/// has been taken direct from a modern digital camera. Digital cameras  record a thumbnail image
/// for their own internal processing. This thumbnail "lives" with the metadata, e.g. EXIF tags that
/// record other information such as when the image was taken, the various camera settings etc.
/// </para>
/// <para>
/// If the string representation of the value does not represent a valid file, or the file is not accessible
/// for any reason then a default image will be returned.
/// </para>
/// <note>If this converter is used with a non-string value it will perform a <c>ToString()</c> on
/// the method in order to generate a string which will then be translated to a URI used to
/// load the image.</note>
/// </remarks>
/// <example>
/// The following example shows how the converter can be used in XAML.
/// <code lang="XML" title="Using the UriToThumbnailConverter in XAML" numberLines="true">
/// &lt;converters:UriToThumbnailConverter x:Key="uriToThumbnailConverter"/&gt;
/// ...
/// &lt;Image Source="{Binding Path=FilePath, Converter={StaticResource uriToThumbnailConverter}}" Height="90" /&gt;
/// </code>
/// </example>
public class UriToThumbnailConverter : IValueConverter
{
/// <summary>
/// Converts a string containing an image path (URI) into the thumbnail <see cref="BitmapSource">bitmap</see>
/// image contained within the image.
/// </summary>
/// <param name="value">The value produced by the binding source.</param>
/// <param name="targetType">The type of the binding target property.</param>
/// <param name="parameter">The converter parameter to use.</param>
/// <param name="culture">The culture to use in the converter.</param>
/// <returns>
/// A converted value. If the method returns <see langword="null"/>, the valid <see langword="null"/> value is used.
/// </returns>
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
try
{
BitmapFrame bitmap = BitmapFrame.Create(new Uri(value.ToString()), BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand);
return bitmap.Thumbnail;
}
catch
{
return System.Drawing.SystemIcons.Exclamation.ToBitmap();
}
}

So what’s the solution?

Well – back in those Visual Studio 2005 days I used to use a little tool called CR_Documentor which was written as a DXCore add-in. This provided a real-time preview window of what your source comments would look like once marked-up. This was really useful as there was nothing more annoying that doing a whole bunch of source comments only to find the next day (after the nightly documentation was produced) I had made some silly error with my markup causing corrupt, incomplete or missing documentation. Admittedly the build I was using used to struggle keeping up with some of the really large namespace documentation (e.g. 500+ lines), but it did a good job for the small stuff.

Configuration settings for CR_Documentor.

But please Microsoft, I want more!

What I really want is source comment markup integrated in the Visual Studio editor. When I’m browsing source code I don’t want to see angle brackets and tags all over the place. I want to see clearly readable documentation. When I want to edit the source comments then you can show me the angle brackets. Or better yet – given only a limited set of documentation and standard HTML tags are supported – why should I ever need to see the tags? Give me a limited document editor with a set of extendable “regions” and some basic bold/italic etc. formatting. (Click the image below to see in its full glory what could be a preview of Dev10).

Visual Studio Help Editor

An impression of what source code comment viewing could be like in Visual Studio.

So everyone knows that fixed-width fonts are out, and more readable proportional fonts are in. So why can’t we also get some WYSIWYG capabilities in the editor?

Some features of the new inline WYSIWYG source comment editor:

  1. Comments can be collapsed completely, or to a single line (as per existing region style collapse) using the expand collapse arrow to the left of the class/member. (Not sure how the arrow does a three state collapse – but hey why not?)
  2. Comment sections can each be collapsed to the heading as per MSDN comments.
  3. Default collapse settings for comments are configurable via Visual Studio settings.
  4. It should look nicer than my hacked “Frankenstein” screenshot which is more or less just overlaying the Sandcastle output over a Visual Studio editing window. In particular the comments should be de-emphasized.
  5. Hmm… what else?

Resources:

Sandcastle – Microsoft’s source code documentation engine

Sandcastle Help File Builder – NDoc-like GUI for Sandcastle

GhostDoc – does a “spooky” job of commenting your code for you.

CR_Documentor – real-time preview window of source comments marked up

XML Documentation Comments Guide – explains the various comment tags for VS 2003, 2005, NDoc and Sandcastle

Is Blend a better WPF designer for developers than Visual Studio?

For ages now I’ve had some XAML that consistently generates error messages in the Visual Studio designer. I’ve found this most frustrating because I was never sure quite what was wrong with the XAML. Compiling and running the application and it worked exactly how it was intended. But the designer simply refused to display it – instead giving this standard message.

Cider Invalid XAML Message 

In the Error List I find:

Cider Invalid XAML Error

Huh? Sure indexes “Must be non-negative and less than the size of the collection.” that makes sense. But which index? Line ‘1’ Position ‘616’ simply refers to the DataTemplate definition – but the whole template is considered “in error”.

The application runs and renders perfectly. It only happens with DataTemplates and I get squiggly lines on the entire DataTemplate so tracking down the exact cause is difficult. Something to do with data-binding is about as close as I got before deciding that I could live without the preview (since I don’t actually use the designer for editing).

So last night – inspired by some of the latest Mix08 videos up on WindowsClient.NET I decided to download and try the latest Expression Blend 2.5 Preview. This last time I used Blend was a pre release 1.0 Beta – and I have to say this program has come a long way since then. My initial impression on the v2.5 Preview are very positive. It’s got a whole heap of features that I wish the Visual Studio designer included:

  1. Resource Viewer!
  2. Binding Editor
  3. Better XAML validation

Better XAML Validation? Yep – take for instance problem I was having with my DataTemplates. Loading this UserControl into Blend I was disappointed to find that it also didn’t render. But lo-and-behold it included errors messages indicating its dislike of my method of binding. Must nicer than the “Index was out of range” error reported by Visual Studio for the same control XAML. Instead for each Binding in the DataTemplate I got the following error:

“The property “Path” is set multiple times.”

Ok – so still not great – but at least it had identified each line within the template that it didn’t like and let me know it was something to do with the data-binding. Now as it turns out I had coded the Bindings as:

<TextBlock Text="{Binding TemplateBinding, Path=Name}" .../>

Why am I using TemplateBinding within a DataTemplate? I dunno – seemed to make sense when I did it and given that it ran without complaint the first time I never blinked an eye – just kept on doing it. So taking out the TemplateBinding my Binding is just…

<TextBlock Text="{Binding Path=Name}" .../>

and hey-presto Blend renders my UserControl without a glitch. Beautiful!

Thinking that at last I had solved the mystery of my missing XAML previews in Cider I flicked back to Visual Studio sharing the same project and re-opened the UserControl. Nope – same error. Recompiled the project – nope same error. Bummer . So its something that doesn’t generate errors at run-time, is not a problem with Blend, but which causes the Visual Studio designer to barf?

So ignoring issues around availability/pricing should developers be using Blend in preference to Visual Studio for authoring XAML? Or is Dev10 going to address the shortfall of Cider vs. Blend. I can understand that Blend is geared for UX designers and as such the two products have different end-users in mind but surely Resources and Binding is something a developer needs to be able to manage effectively?

Great Content Abounds

Haven’t posted for a while – I’ve been absorbing the flurry of good content that been blogged recently. Some of my favourites.

Prism

  • RI drops every couple of weeks – its interesting watching the bits take shape. I wish they’d include source comments though. I’m guessing they think its less cluttered without the comments but I find it tedious drilling down into every class/interface/member to try and work out its use. Maybe I’m not familiar enough with some of the pattern implementations – but surely if “learnability” is as higher on the priority list as suggested…
  • I wonder if they strip the comments out when the drop a release or whether they really have no source comments at all?
  • The latest drop shows the teams current thoughts on implementing a Command pattern using a customised ICommand implementation.
  • I really like the Region Manager stuff, using an attached property to allow any Panel or ItemsControl to become a region with a single XAML attribute.
  • I also found Ward Bell’s post on “Prism Camp” describing the working party that was put together to help kick off the project quite fascinating. [Side note to self: Ward is the product manager for DevForce.NET – interesting.]

Unity

  • Having some fun playing with Inversion of Control (IoC) in my test app. Whilst its got some great advantages its interesting to consider at what point that added complexity outweighs the gains – e.g. at what size/complexity of app does it become worthwhile. (Note the documentation does contain guidance on that question).
  • I first looked at this via its use in the earlier Prism drops but I notice that its just been officially released.

Josh Smith’s WPF Bootcamp Video

  • Where he walks through his demo X-tray WPF app. Definitely worth checking out if you’re interested in MVP/MVC etc. implementations for WPF. Great stuff.

Karl Schifflet’s next WPF Business Application instalment

Rob Relyea

  • This guy is blogging links to some great content (including most of the above) almost as fast as I can consume it!