Colin Eberhardt's Technology Adventures

Automatically Showing ToolTips on a Trimmed TextBlock (Silverlight + WPF)

January 31st, 2011

Both WPF and Silverlight have a property TextTrimming=”WordEllipsis”, which trims the text that a TextBlock displays based on the available width. This blog post describes a simple method for automatically showing the full text as a tooltip whenever the text is trimmed. This is presented as an attached behaviour and works in both WPF and Silverlight

A few weeks ago I blogged about a Silverlight solution for automatically adding tooltips when a TextBlock Text is trimmed and renders an ellipsis. I found a decent looking WPF solutions on the web and linked it in my article, however, based on the comments to my previous blog post, it looks like the WPF solution didn’t work too well, failing to respect font size etc… In this blog post I have updated my solution to be cross-platform, working on WPF and Silverlight.

To briefly recap, my solution for automatically adding tooltips to trimmed text relies on the slightly odd behaviour of the TextBlock where its ActualWidth is reported as the width of the text without trimming:

In order to determine whether to show a tooltip, all you have to do is compare the ActualWidth of the TextBlock to the ActualWidth of its parent.

However, the WPF TextBlock does not have this same quirky behaviour, so a completely different approach is required. The other solutions I have seen involve using the low-level WPF drawing APIs to compute the size of the rendered text, however, there is a simpler solution to this problem …

UPDATE: I originally wrote about a method of finding the overall text width from various internal fields within the TextBlock via reflection, as shown below. However, a kind reader of my blog, Daniel Fihnn, pointed out that there is a simpler solution that does not require any reflection.

Daniel pointed out that the width of the TextBlock without the trimming can be obtained using the Measure method. This method is typically used by panels during layout, the Measure method is invoked with the size made available to the element, calling this method causes the element to update its DesiredSize property. Therefore, if you invoke Measure on a TextBlock which has trimming enabled, giving it an infinite available space, its DesiredSize property will report the width that the text would occupy without trimming.

The ComputeAutoTooltip method of the attached behaviour I described in my previous post is updated to have a completely different WPF implementation:

public class TextBlockUtils
{
  /// <summary>
  /// Gets the value of the AutoTooltipProperty dependency property
  /// </summary>
  public static bool GetAutoTooltip(DependencyObject obj)
  {
    return (bool)obj.GetValue(AutoTooltipProperty);
  }
 
  /// <summary>
  /// Sets the value of the AutoTooltipProperty dependency property
  /// </summary>
  public static void SetAutoTooltip(DependencyObject obj, bool value)
  {
    obj.SetValue(AutoTooltipProperty, value);
  }
 
  /// <summary>
  /// Identified the attached AutoTooltip property. When true, this will set the TextBlock TextTrimming
  /// property to WordEllipsis, and display a tooltip with the full text whenever the text is trimmed.
  /// </summary>
  public static readonly DependencyProperty AutoTooltipProperty = DependencyProperty.RegisterAttached("AutoTooltip",
          typeof(bool), typeof(TextBlockUtils), new PropertyMetadata(false, OnAutoTooltipPropertyChanged));
 
  private static void OnAutoTooltipPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  {
    TextBlock textBlock = d as TextBlock;
    if (textBlock == null)
      return;
 
    if (e.NewValue.Equals(true))
    {
      textBlock.TextTrimming = TextTrimming.WordEllipsis;
      ComputeAutoTooltip(textBlock);
      textBlock.SizeChanged += TextBlock_SizeChanged;
    }
    else
    {
      textBlock.SizeChanged -= TextBlock_SizeChanged;
    }
  }
 
  private static void TextBlock_SizeChanged(object sender, SizeChangedEventArgs e)
  {
    TextBlock textBlock = sender as TextBlock;
    ComputeAutoTooltip(textBlock);
  }
 
  /// <summary>
  /// Assigns the ToolTip for the given TextBlock based on whether the text is trimmed
  /// </summary>
  private static void ComputeAutoTooltip(TextBlock textBlock)
  {
#if WPF
    textBlock.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
    var width = textBlock.DesiredSize.Width;
 
    if (textBlock.ActualWidth < width)
    {
      ToolTipService.SetToolTip(textBlock, textBlock.Text);
    }
    else
    {
      ToolTipService.SetToolTip(textBlock, null);
    }
 
#else
    FrameworkElement parentElement = VisualTreeHelper.GetParent(textBlock) as FrameworkElement;
    if (parentElement != null)
    {
      if (textBlock.ActualWidth > parentElement.ActualWidth)
      {
        ToolTipService.SetToolTip(textBlock, textBlock.Text);
      }
      else
      {
        ToolTipService.SetToolTip(textBlock, null);
      }
    }
#endif 
  }
}

This code now works in both a WPF and a Silverlight context. Here’s a screenshot of it working in WPF:

You can download the full sourcecode, including the WPF and Silverlight demo: AutoTooltipTextBlock.zip

Thanks to Daniel Fihnn for a much improved WPF version of this code!

Regards, Colin E.

Does HTML5 mean the end is in sight for Silverlight?

November 2nd, 2010

This blog post looks at the fallout after last week’s PDC conference where Microsoft were quoted as saying “our strategy on Silverlight has shifted”, and the resulting fallout in the developer community. In this post I will describe why I think Silverlight has a future ahead of it and exactly where that future lies.

Bob Puts His Foot In It!

Last week’s Microsoft Professional Developer Conference (PDC) has caused quite a stir. It was clear from Steve Ballmer’s keynote speech that HTML5 was taking centre stage, with Silverlight not getting a single mention in his opening speech.

The image below shows a word cloud showing the most frequent words in Steve Ballmer’s PDC keynote speech, rendered using Wordle

This is in contrast to previous events such as MIX9 where (just over a year ago) Silverlight 3 took centre stage. This focus on HTML5, which many see as a competing technology to Silverlight was enough to get the community a little worried, however, it was the interview that Bob Muglia gave to ZDNet that really caused a storm.

The key quotes are given below:

“[...] when it comes to touting Silverlight as Microsoft’s vehicle for delivering a cross-platform runtime, our strategy has shifted.”

“But HTML is the only true cross platform solution for everything, including (Apple’s) iOS platform”

The above statements caused quite a stir, with calls for Bob to clarify his statements which seemed to contradict the recent “Future of Silverlight” blog post which contrasted the difference between standardisation (HTML5) and innovation (Silverlight) to show a very positive future for the technology. I think this is the first time I had seen such a direct comparison of HTML5 vs. Silverlight from Microsoft’s Silverlight team, and the arguments they made were quite compelling.

Bob Pulls His Foot Out Again

As a result of Bob’s interview, which was commented upon by virtually everyone in the Silverlight community (Jeremy Likeness, Mike Taulty, and many many more), Bob quickly followed up with a blog post where he stated the following:

“I said, ‘Our Silverlight strategy and focus going forward has shifted.’ This isn’t a negative statement, but rather, it’s a comment on how the industry has changed and how we’re adapting our Silverlight strategy to take advantage of that”

However, I think that the most important point he made came at the very end of his post:

“The purpose of Silverlight has never been to replace HTML, but rather to do the things that HTML (and other technologies) can’t, and to do so in a way that’s easy for developers to use.”

I think it is people’s misunderstanding of the differences between Silverlight and HTML that caused most of this uproar in the first place. It is this point which I would like to concentrate on, and hopefully provide a bit more clarity.

PDC is an Event

Before I focus on the differences between HTML and Silverlight I think it is worth noting that PDC is an event, and just like any other event it needs to be marketed in order to fuel people’s interest and get them through the door. Microsoft embraces a very wide range of technologies, and if the PDC tried to be a true reflection of this diversity it would be very fragmented and hard to market. It is much better that the event focuses on something new and interesting to provide an underlying theme. This year that theme was HTML5.

Interestingly after MIX9 where Silverlight was the main focus and out-of-browser support was announced, there was noticeable unrest amongst the WPF community, they felt short-changed (4 MIX sessions on WPF to Silverlight’s 31) and there was speculation that Silverlight would replace WPF entirely. However, when the knee-jerk reactions were forgotten about and a more sensible analysis of the difference between the two was considered (see Pete Brown’s Future of Client App Development blog post for example), it was clear that WPF does have a future.

The Web Landscape

Back to HTML and Silverlight, if we look at the current landscape of the internet we can crudely characterise web sites and web based applications based on the degree of interactivity that provide:

In the above diagram we see a sliding scale of interactivity and complexity with a few well known sites positioned along this scale (don’t ask me about what units I am using to measure each site!).

With the above sliding scale we can position the popular internet technologies based on their relative strengths and the types of site they are most suited to:

I have not tried to pin each technology to a specific location on the scale because in my opinion the boundaries between each are blurred … a lot. It is possible to use any of the above technologies to create a web site / web application at either end of the spectrum, however, the further away you move from the ‘comfort zone’ of each technology, the harder the job becomes.

We’ll start at the Flash / Silverlight end of the spectrum. Why not capitalise on the fact that these plugin technologies provide a controlled environment for your code to run in, providing great performance and virtually zero browser compatibility issues?

Whilst this point may not have been addressed in great detail for Silverlight, there are certainly numerous strong arguments presented on the internet which describe quite clearly why full-page Flash sites will never fully replace HTML (For a thorough analysis take a look at Emil Stenström’s blog post on Flash vs. Ajax sites). The main reasons cited are:

  • Splash screens – Flash / Silverlight sites need to load the entire ‘executable’ before they can render. Contrast this with how quickly the pages from Wikipedia appear.
  • Maintenance – Quick fixes are often required for websites, with HTML / JavaScript this can often be left to the support team. For Silverlight / Flash this requires a full rebuild of the application.

(There are a number of other points, including search engine indexing, etc …)

There is not a strong case for replacing simpler web sites with Silverlight. I think my fellow WPF Disciple Justin Angel’s blog, which is powered entirely with Silverlight is unfortunately a good illustration of why Silverlight should not be used to replace HTML for the presentation of largely static content. Sitting here on a train using the pitiful WiFi connection I can see Justin’s stylish loading ‘splash screen’, however, after I minute of waiting I grow tired of staring at his beard and sunglasses and little else!

On the flip-side, when HTML and JavaScript technologies are used to create complex applications, development becomes costly and complex. Cross-browser problems, lack of support for business concepts such as controls and validation, performance issues all start to have a significant impact on the development. To combat this more and more sophisticated solutions are being applied, from the numerous libraries that abstract the differences in browser DOM APIs (jQuery etc…) to Google Web Toolkit, which generates JavaScript code from Java (which provides strong typing and better structuring).

Interestingly in the book Google Closure the Definitive Guide, the preface describes how Google Closure (a JavaScript compiler and mechanism for checking types) was developed to combat the problems the Google Mail development team were experiencing in developing a complex JavaScript application composed of tens of thousands of lines of JavaScript. The take-home message of this is that for complex applications you need more than the JavaScript language alone provides.

Bob’s Comments in Perspective

In the previous section I described how the web landscape can be illustrated as a sliding scale of complexity, with HTML and Silverlight at opposite ends of the spectrum and HTML5 sitting somewhere in-between. With this in mind, Silverlight developers should not fear that HTML5 will replace Silverlight. Whilst it is true that there is some common ground between the two, i.e. a certain interactivity / web-site complexity where the two technologies are equally suited, Silverlight users should feel comfortable that for the more complex problems, Silverlight has a clear advantage.

To repeat Bob’s closing statement of his follow-up blog post:

“The purpose of Silverlight has never been to replace HTML, but rather to do the things that HTML (and other technologies) can’t, and to do so in a way that’s easy for developers to use.”

I think it is the failure of the developer community to realise that there is little direct competition between HTML5 and Silverlight and failure of Microsoft’s marketing to highlight this.

The Web Increases its Reach.

However, there are some important points to note in Bob’s comments and his reference to iOS (i.e. iPhone, iPad etc…). Whilst I do not think HTML5 is a significant threat to Silverlight for web based application development, the introduction of a more diverse range of mobile devices potentially increase the market for HTML.

Most people who use an Android phone or an iPad do not use them as a replacement for their laptop or desktop PC. They use them on the train, in the coffee shop and at home on the sofa as a way to stay online and connected for more of their waking hours. HTML5 is a suitable technology for delivering a interactivity to a diverse range of devices and it looks like the overall market size is increasing.

However, if Microsoft can produce Silverlight plugins for these devices, on the Android phone for example, there is no reason why Silverlight cannot be part of this growing market, delivering more than just interactivity to the mobile platform.

Unfortunately, more recent news, like today’s announcement by the Bing Maps team that seems to indicates they will be dropping their Silverlight based 3D libraries in favour of HTML5 is going to fuel the fire which Bob and Steve Ballmer are currently trying to dowse.

Regards, Colin E.

White Paper: Silverlight, WPF and Windows Phone 7 cross platform development

October 11th, 2010

Last week I gave a presentation at a joint Scott Logic / Microsoft event about how WPF and Silverlight are unifying the development platform for desktop, web and mobile. To accompany the talk I wrote a white paper which delves into this subject in a little more detail.

You can download the whitepaper here: WPF and Silverlight Cross Platform Development White Paper (PDF, 1.8 MBytes)

Or view it online in the PDF viewer below:

I also created a cross platform application that has a 75% shared codebase between the WPF (desktop), Silverlight (web) and Windows Phone 7 (mobile) versions. I plan to share more of this at a later date.

Any thoughts, ideas or comments, please share them below.

Regards,
Colin E.

Templates, or Why I love WPF (and Silverlight Too!)

September 10th, 2010

This post compares the implementation of a simple ListBox layout with Windows Forms and Windows Presentation Foundation. The use of Templates within WPF are a clear winner over the WinForms ‘owner draw’ route.

Application user interfaces are becoming much more graphical, with users expecting a more engaging and ‘lively’ experience. However, rich graphical UIs can do much more for the user than just provide an experience that looks and feels good. Graphics can be used to more effectively convey the options available to the user. For example, which of these line weight selectors would assist best in helping a a user determine a suitable selection …

I think most users would prefer the second option where they can visualise a range of line weights and actually see how they look (after all, how many users know what a ‘pt’ actually is?) before making a selection. However, for a Windows Forms developer, the first option, a simple text box with the label ‘pt’ next to it, is trivial to implement, whereas the second is not.

Applications such as Word 2007 present as many of the user options as possible in a visual style, for example, the font selector in previous versions of Word simply presented a list of font names, whereas in Word 2007 each font is rendered as it would appear to the user. Furthermore, the font selector combo-box is grouped to include recently used fonts:

Unfortunately for the developer, creating visual UIs can be quite challenging.

Windows Forms has been the technology of choice for the creation of business desktop applications for a number of years. The developer is presented with a large number of standard controls with which they can build their application, however these controls lack the flexibility required to create a more visual interface. For example, combo-boxes and list-boxes are designed to render text content, not mixed font text with icons, or lines of varying weight as seen in our above examples. To create a control that renders non-standard content, the only route available to the developer is ‘owner draw’ where the developer handles events in order to render all or part of the control. This is a time consuming and highly iterative process, with the developer having to compile and run their code repeatedly to see the results of their graphics code.

One of the key differences between Windows Forms and WPF is the way in which the visual representation of controls and their content is encoded. WPF has the concept of templates, an XML (or more accurately XAML) representation of how a control is rendered to the screen. This is what allows WPF developers / designers to create funky looking round buttons and other impressive UI fluff! However, probably of more interest to developers of business applications are data templates, which detail how data is represented on the screen.

Controls such as list-boxes and combo-boxes are used to represent, and provide selection from, a list of data objects. With the WPF framework, the way in which this data is represented is specified by a DataTemplate. We’ll take a look at how this differs from the WinForms owner-draw route by rendering the same content with each technology.

There are quite a few articles available on the internet which describe how to create an owner draw listbox. I took the sourcecode from an article on codeproject by GiedriusBan, his article describes how to owner-draw a listbox to add some more complex content into each item:

Because the listbox is being used to render more than just text, the only viable solution is to ‘owner draw’ each listbox item, this is done by handling an event provided by the listbox and the following GDI graphics code:

public void drawItem(DrawItemEventArgs e, Padding margin, 
                        Font titleFont, Font detailsFont, StringFormat aligment, 
                        Size imageSize)
{
    bool isHighlighted = (e.State & DrawItemState.Selected) == DrawItemState.Selected;
 
    // if selected, mark the background differently
    e.Graphics.FillRectangle(isHighlighted ? Brushes.DarkBlue : Brushes.White, e.Bounds);
 
 
    // draw some item separator
    e.Graphics.DrawLine(Pens.DarkGray, e.Bounds.X, e.Bounds.Y,
                               e.Bounds.X + e.Bounds.Width, e.Bounds.Y);
 
    // draw item image
    e.Graphics.DrawImage(this.ItemImage, e.Bounds.X + margin.Left,
                                  e.Bounds.Y + margin.Top, imageSize.Width, imageSize.Height);
 
    // draw a border around the image
    e.Graphics.DrawRectangle(Pens.DarkGray, e.Bounds.X + margin.Left, e.Bounds.Y + margin.Top,
                                       imageSize.Width, imageSize.Height);
 
    // calculate bounds for title text drawing
    Rectangle titleBounds = new Rectangle(e.Bounds.X + margin.Horizontal + imageSize.Width,
                  e.Bounds.Y + margin.Top,
                  e.Bounds.Width - margin.Right - imageSize.Width - margin.Horizontal,
                  (int)titleFont.GetHeight() + 2);
 
    // calculate bounds for details text drawing
    Rectangle detailBounds = new Rectangle(e.Bounds.X + margin.Horizontal + imageSize.Width,
                    e.Bounds.Y + (int)titleFont.GetHeight() + 2 + margin.Vertical + margin.Top,
                    e.Bounds.Width - margin.Right - imageSize.Width - margin.Horizontal,
                    e.Bounds.Height - margin.Bottom - (int)titleFont.GetHeight() - 2 - margin.Vertical - margin.Top);
 
    // draw the text within the bounds
    var brush = isHighlighted ? Brushes.White : Brushes.Black;
    e.Graphics.DrawString(this.Title, titleFont, brush, titleBounds, aligment);
    e.Graphics.DrawString(this.Details, detailsFont, brush, detailBounds, aligment);            
 
    // put some focus rectangle
    e.DrawFocusRectangle();
 
}

This is a lot of ‘heavy’ and hard to follow graphics code to achieve such a simple listbox item layout!

With WPF the listbox uses a template to render the data within the list. Here is the same list rendered with a WPF application:

And here is the XAML code to create this layout:

<ListBox Margin="5" ItemsSource="{Binding}"
            ItemContainerStyle="{StaticResource StretchedContainerStyle}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid HorizontalAlignment="Stretch">
                <Grid Margin="5">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition/>
                    </Grid.RowDefinitions>
 
                    <Border  Grid.RowSpan="2"
                                BorderBrush="LightGray" BorderThickness="1"
                                Margin="0,0,5,0">
                        <Image Source="{Binding Image}"/>
                    </Border>
                    <TextBlock Text="{Binding Name}"
                                FontWeight="Bold"
                                Grid.Column="2"
                                Margin="0,0,0,5"/>
                    <TextBlock Text="{Binding Details}"
                                Grid.Column="2" Grid.Row="2"/>
                </Grid>
                <Line X1="0" Y1="0" X2="1" Y2="0" Stretch="Uniform"
                        Stroke="DarkGray"
                        VerticalAlignment="Bottom"/>
            </Grid>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Comparing the two approaches; not only is there less code in the WPF version, it is also much clearer and easy to follow. However, the advantages of the WPF approach do not end there …

WPF uses a retained graphics mode, which means the various elements in the above XAML code are assembled into a visual tree that is retained in memory, rather than just being painted to some bitmap. This means that the developer does not have to worry about invalidation, and does not need to employ techniques to avoid flicker when re-drawing.

The original author of the WinForms code above subclassed ListBox and created a concrete control for rendering this specific data with this specific layout. With WPF there is no subclassing, and no need to create a specific ListBoxItem for each row to provide the data for the control, instead the list binds directly to the business objects, with the DataTemplate doing all the work.

Finally, you can supply design time data to your WPF / Silverlight applications, allowing you to get immediate feedback when designing your templates, removing the time consuming build / execution cycle required with WinForms. The screenshot below shows how the listbox looks in visual studio:

And here is the design time data:

<PersonCollection xmlns="clr-namespace:TemplatedListBox">
    <Person Name="John, the Tester"
            Details="First details text is used to check it out"
            Image="image1.jpg"/>
    <Person Name="John, the Tester"
                Details="First details text is used to check it out"
                Image="image2.jpg"/>
</PersonCollection>

In conclusion, templates are a very powerful features of the WPF (and Silverlight) framework that provide far more that just a mechanism for creating round buttons! If we look at the font selector used in Word 2007, I can imagine creating this UI with WPF in a matter of hours, whereas with WinForms it would take days. That is why I love WPF!

You can download the WPF and WinForms source for this article: WPFLove.zip

Regards, Colin E.