Annotated FlowDocument Viewer with Comments Pane


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!

Annotated Document Viewer.zip

Comments (3)

  1. A new WPF 3.5 feature in the Annotations area is the capability to match annotations with the corresponding

  2. adajos says:

    This was a great sample app!  The information out there on Annotation in WPF is pretty sparse thus far.  

    Here’s my question: I need to be able to Annotate the Annotation and have it show exactly who said what on a sticky note–just having a list of the authors at the bottom of the note without specifiying which actual text they wrote won’t do it.

    I have 2 ideas for how to accomplish this. One would be just appending the author name (after base 64 encoding it) to the annotation and then somehow making that ineditable to other authors via styling, while still allowing the other authors to append their own comments to it.  Seems pretty tough and kludgy.

    The other idea might work better.  When a user clicks on the little document to show the StickyNote, check to see if the AnnotationService’s Store contains any other Annotations with the same anchor.  That should be possible by comparing the TextPointers for BoundingStart and BoundingEnd obtained via the GetAnchorInfo method.  But somehow events and/or new commands would need to be written that would then bring up ALL sticky notes associated with a given anchor at the same time, so an audit trail of comments/times/authors can be viewed.

    Right now I’ve noticed that if multiple annotations have the exact same anchor there’s no visual way to discern that.  Rather, when you expand the sticky note it advances through the list of annotations and shows the "next" one each time.

    Any thoughts on this???!!!

    Thanks,

    Josh

  3. globbe says:

    I was very happy learn about the addition of the IAnchorInfo interface to the framework, however I have run into some problems when trying to use it with annotations in Fixed Documents. I have written about it here:

    http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2022956&SiteID=1

    and I would be most grateful if you had any tips or ideas on how to solve this issue…

    thank you.

Skip to main content