Microsoft Communities

Welcome to WindowsClient.net | Sign in | Join

How To: Customizing the Appearance of Articles

The SCE Reader Sample ships with several components that will help you display beautiful full-text articles. A handful of helper classes allow you to customize the appearance of articles for the most common scenarios with very little additional effort. In addition, the SCE Reader Sample furnishes you with several extensibility mechanisms that allow an even greater level of control over the appearance of your content.

Understanding FlowDocument Conversion and Article Formatting

The following figure depicts the flow of data as an article is transformed from XML to an on-screen FlowDocument object.

An outline of the process is as follows:

  1. A request for story is made via a DataManager object (typically in response to user input).
  2. The full-text XML is passed to a document converter. By default, this is the NitfToFlowDocumentConverter object. The NitfToFlowDocumentConverter object creates a FlowDocument object from the XML and applies styles found in the FlowDocumentStyleProvider class. Images and ads are not inserted at this point.
  3. The FlowDocument object is passed to the StoryViewer object. The StoryViewer object begins the layout process, which depends on the user’s window size, resolution, and so on.
  4. As the StoryViewer object paginates the document, images and ads are inserted according to the rules specified through the PageTemplateCollection class.
  5. On the last page, additional content is inserted according to the blank-area templates.

Customizing Article Appearance with a FlowDocumentStyleProvider Class

As a convenience, the SCE Reader includes a class named FlowDocumentStyleProvider. This class allows you to use XAML and declaratively specify many of the properties that affect article appearance. A sample FlowDocumentStyleProvider class is provided as part of the SCE Reader Sample application. You can find the class in the Articleresources.xaml file in the Resources folder. You can edit this file to change the appearance of stories.

The styles are very straightforward and therefore will not be covered in this article.

Using Custom Fonts

One of the most powerful ways for publishers to customize the SCE Reader Sample application is by using custom fonts. For example, imagine that you have a custom font in a file named MyCustomFont.otf. You can use this font as follows:

  1. Add the font to the Resources folder (right-click Resources, click Add, click Existing Item, and then select the font file from disk).
  2. Change the style to reference this font. The code looks like this:
<Style x:Key="ArticleTitleStyle" TargetType="{x:Type Figure}">   <!-- ... -->   <Setter Property="FontFamily" Value="/Resources/#MyCustomFont" />   <!-- ... --> </Style>

After the font has been added to the Resources folder, you can reference the font anywhere in the application by using "/Resources/#MyCustomFont” as the font family.

Controlling Image and Ad Placement with Page Templates

To provide the highest-quality reading experience, images and ads are always snapped to column widths. We also attempt to guarantee that at least one image or ad appears on each page. These guidelines mean that images and ads cannot be inserted into the FlowDocument object as it is programmatically generated from XML. In order to achieve these results, a helper class named ViewInsertionManager inserts these objects into the document when the document appears on screen.

To simplify the process of placing images and ads on a page, the ViewInsertionManager consumes PageTemplate objects. A PageTemplateCollection object specifies the layout of images and ads for every page of an article except the last page. The following example shows a PageTemplateCollection declaration.

<SceReaderData:PageTemplateCollection x:Key="DefaultPageTemplateCollection">
  <SceReaderData:ImagePageTemplate VerticalAnchor="ContentBottom" />
  <SceReaderData:AdPageTemplate Width="1Column" MinHeight="50px" MaxHeight="1Column"/>
  <SceReaderData:AdPageTemplate Width="2Column" MinHeight="50px" MaxHeight="0.5Column" VerticalAnchor="ContentBottom"/>
  <SceReaderData:AdPageTemplate Width="1Content" MinHeight="50px" MaxHeight="0.3Column" VerticalAnchor="ContentBottom" HorizontalAnchor="ContentCenter"/>
</SceReaderData:PageTemplateCollection>

When a story is displayed on the screen, the ViewInsertionManager object sequentially consumes these PageTemplate objects to reserve space for images and ads. Each PageTemplate instance corresponds to a single page. If there are more pages in the article than PageTemplate instances, the ViewInsertionManager object loops back through the collection. If there are fewer pages than PageTemplate instances, the last PageTemplate objects are ignored.

There are two types of PageTemplate: ImagePageTemplate and AdPageTemplate. On a given page, the ViewInsertionManager object will insert either an image or an ad, but not both.

ImagePageTemplates

By default, the ViewInsertionManager class inserts images and configures them to display as large as possible without overscaling them. The exception is when an article would take up only one page. Instead of pushing the image onto a blank second page when it collides with the headline figure, the ViewInsertionManager attempts to scale the image down to fit on the first page.

You cannot specify the image size in the ImagePageTemplate object. However, you can specify the horizontal and vertical anchors. If you need more flexibility over image sizing, consider overriding and extending ViewInsertionManager.

AdPageTemplates

The AdPageTemplate class affords you more control than the ImagePageTemplate class because you can specify size constraints. For the ad width, you can specify an integer number of columns or “1Content” (the ad spans the entire document width). Ad heights are given in ranges and can be specified in pixels or as a fraction of the column height. As with ImagePageTemplate, you can also specify horizontal and vertical anchors.

Customizing blank space on the last page

Effectively using the blank space on the last page of an article requires special consideration. Bear in mind that the last page of a one-page article is the first page. This blank space is divided into two separate regions: ColumnBlankAreaSpace and PageBlankAreaSpace. The content in these regions is specified by specifying a LastPageTemplate object.

Column Blank Area

The column blank area is the region directly below the last column of text. Content in this region is provided by a SizeTemplateControl object, which allows you to specify a collection of templates that are selected based on the size of this region. In the SCE Reader Sample application, we specify a single template in the ColumnBlankAreaTemplates collection. This template displays a simple water mark.

Page Blank Area

The page blank area region consists of all the columns on the last page that are completely blank. Content in this region is provided by a SizeTemplateControl object, which allows you to specify a collection of templates that are selected based on the size of this region. In the SCE Reader Sample application, we specify a single template in the PageBlankAreaTemplates collection. This template displays an ad which fills the entire available space.

Images on a Single Page Article

It is possible to display an image on the last page, and this is typically desirable for one-page articles. The layout behavior for this image is specified by the SinglePageImageTemplate object. We recommend that you set HorizontalAnchor to ContentLeft. If you anchor the image to the right side of the page, you might encounter scenarios where the image is separated from the last column of text by one or more blank columns.

Frequently Asked Questions (FAQ)

Can I make stories in different sections have different styles?

Certainly. The SCE Reader Sample has several extensibility mechanisms that you can use to do this. Two possible ways of doing this are as follows:

  1. Extending with differences only in styles: Define multiple FlowDocumentStyleProvider classes. Override the Convert method of the NitfToFlowDocumentConverter class and pass the appropriate style provider to the GetFlowDocumentFromNavigator method.
  2. Extending with more dramatic differences (for example, putting the byline above the headline): If you require multiple styles, define multiple FlowDocumentStyleProvider classes. Also define multiple methods using the model of GetFlowDocumentFromNavigator. Override the Convert method of NitfToFlowDocumentConverter and pass the appropriate style provider to the appropriate GetFlowDocumentFromNavigator method (such as GetSportsFlowDocumentFromNavigator). Override the RegisterConverters method of the ServiceProvider class, where you unregister the old FlowDocument converter class and register your new one.

Do I have to rely on ViewInsertionManager to insert images?

Not always. In certain scenarios, ViewInsertionManager may not be your best option for inserting images. For example, a technical journal might have 10 figures in an article and they should appear interspersed densely throughout the content. In that case, it might be more appropriate to insert the images during the conversion from XML to FlowDocument. You will want to use the SceReader application’s ImageControl class, which handles asynchronous image loading from the application cache for you.

Bear in mind that the ViewInsertionManager class is extensible. Depending on the scenario, it might make sense to create a custom document converter, extend ViewInsertionManager, or both.

Can I insert more than one image per page?

Sort of. Using ViewInsertionManager more-or-less guarantees that one image or ad will appear on every page. If you are willing to sacrifice visual quality, you can insert as many images as you want directly into the FlowDocument object. However, you could not ensure that any of these images or ads would appear on a particular page. Always bear in mind that a FlowDocument object that looks good at one screen size may not look good at another.

Can I vary the page templates article by article?

Of course. You can specify additional StoryTemplateSource objects and then override the OnDocumentChanged method of the StoryViewer class to select the appropriate StoryTemplateSource instance.

Why are ad heights given in ranges?

Although most ads adhere to various size standards, the SCE Reader application scales ads within tolerances that you specify to match integer multiples of FlowDocument column width. This allows ads to appear much more naturally within the content. Thus, given a particular screen size and AdPageTemplate object, the width of the ad is fixed. Because the ad will be scaled somewhat to match with this precisely, the height will be scaled as well to preserve the ad’s aspect ratio. You will generally be more successful at placing ads if you give the AdPageTemplate a wide range of heights to select from.

Featured Item

Page view counter