A new WPF 3.5 feature in the Annotations area is the capability to match annotations with the corresponding annotated objects. For example, you can now implement a document viewing application that has a comments pane, where the paragraph that contains the corresponding comment (a text sticky note in this case) is brought into view if you make a selection. A simplified version of such an application may look like this:

 

The list box is bound to the list of annotations. In particular, it uses a converter (IValueConverter) to turn the content of each annotation (64-bit binary data) into text strings. The following is the implementation of the converter:

    public class AnnotationDataConverter : IValueConverter

    {

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

        {

            // Convert 64 bit binary data into an 8 bit byte array and load

            // it into a memory buffer

            byte[] data = System.Convert.FromBase64String(value as string);

            using (MemoryStream buffer = new MemoryStream(data))

            {

                // Convert memory buffer to object and return text

                Section section = (Section)XamlReader.Load(buffer);

                TextRange range = new TextRange(section.ContentStart, section.ContentEnd);

                return range.Text;

            }

        }

 

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

        {

            return null;

        }

    }

The data template that the list box uses does most of the binding work:

    <DataTemplate x:Key="annotationDataTemplate">

      <TextBlock Margin="5" TextWrapping="Wrap">

        <TextBlock FontWeight="Bold" TextWrapping="Wrap">

          [<TextBlock Text="{Binding Path=CreationTime}" />]

        </TextBlock>

        <TextBlock

          Text="{Binding Path=Cargos[1].Contents[0].InnerText,Converter={StaticResource annotationDataConverter}}"

          TextWrapping="Wrap" />

      </TextBlock>

    </DataTemplate>

When you make a selection from the comments pane, this event handler finds out where the annotation is anchored to and brings the corresponding paragraph into view:

        void annotationsListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)

        {

 

            Annotation comment = (sender as ListBox).SelectedItem as Annotation;

            if (comment != null)

            {

                // IAnchorInfo info;

                // service is an AnnotationService object

                // comment is an Annotation object

                info = AnnotationHelper.GetAnchorInfo(this.service, comment);

                TextAnchor resolvedAnchor = info.ResolvedAnchor as TextAnchor;

                TextPointer textPointer = (TextPointer)resolvedAnchor.BoundingStart;

                textPointer.Paragraph.BringIntoView();

            }

        }

This application, which is attached and works with Orcas Beta 2 bits, also sorts the comments by creation time and templates the list box so that it is a text-wrapping scrollable area. Check it out!