WPF FlowDocuments (1) – Images, Shapes and Tables

WPF FlowDocuments (1) – Images, Shapes and Tables

http://vbcity.com/blogs/xtab/archive/2010/03/22/wpf-flowdocuments-1-images-shapes-and-tables.aspx

 

WPF FlowDocuments can be very rich in content.   Mostly you’ll appreciate the ability to lay out text and images in just about any configuration you can imagine.  But in some  circumstances you might need to include other elements, such as shapes, controls or other media elements to a FlowDocument.   We’ll look at each of these in turn over the course of a number blog items.

 

Images
Including an Image in a FlowDocument is relatively simple.  Because it isn’t text, it must be placed inside a BlockUIContainer.  In the example below, I’ve set only the Source and Width properties:

 

                        < BlockUIContainer >

                            < Image Source ="cr2.gif" Width ="150"/>

                        </ BlockUIContainer >

I’ve occasionally had problems with Image Source and have seen error messages along the lines of:

           The file <filename>is not part of the project or its 'Build Action' property is not set to 'Resource'.  

An alternative syntax for assigning the source is to use the Pack URL syntax:

              Source = "pack://application:,,,/WpfRichTextBox;component/cr2.gif"

In the above example, WpfRichTextBox is the name of the project and the xml namespace.   This more verbose but more precise path naming will usually get round file access problems.

By default, the image will have a HorizontalAlignment of Center.  You can change this, just as you would for an element outside of a FlowDocument.

 

        < BlockUIContainer >

          < Image Source ="cr2.gif" Width ="150"

             HorizontalAlignment ="Left" Margin ="10"/>

        </ BlockUIContainer >

As you can see, I’ve also set values on the Margin property to add a little space around the image.

Images Inline
Because you can access the content of a FlowDocument at a very low level, it’s easy to include things like images in line with the text:

FlowDocContent01

 

The trick to doing this is to use an InlineUIContainer and place the Image inside that container:

        < Paragraph > You can search using your preference of

          < InlineUIContainer >

            < Image Margin ="2,0" Width ="50" Source ="bingLogo.jpg" ></ Image >

          </ InlineUIContainer >

          or

          < InlineUIContainer >

            < Image Margin ="2,0" Width ="50" Source ="googleLogo.jpg" ></ Image >

          </ InlineUIContainer >

          .

        </ Paragraph >

You’ll have noticed that the two logos are floating above the line of text. The vertical alignment by default is Center and you can change this by using the BaselineAlignment property of the InlineUIContainer:

 

          < InlineUIContainer BaselineAlignment ="TextBottom" >

            < Image Margin ="2,0" Width ="40" Source ="bingLogo.jpg" ></ Image >

          </ InlineUIContainer >


Although this will bring the logo down slightly, these images aren’t really a very good example.  The reason is that the bottom of each of them is the bottom curl on the drawing of the letter g.    So the best you can really get is this:

 

FlowDocContent02

If I replace those images with one that has a more obvious baseline, you’ll see that it really does work as it should:

FlowDocContent03

Shapes
Shapes can be included in a FlowDocument in just the same way as images.  This ellipse, for example:

FlowDocContent04

The markup is:  

        < BlockUIContainer >

          < Ellipse Fill ="Red" Width ="150" Height ="150" Margin ="5"

                  Stroke ="Black" StrokeThickness ="5" />

        </ BlockUIContainer >

 

If you need something more than the basic shapes, you can create your required shape with a Path and put that in a BlockUIContainer:

 

        < BlockUIContainer >

          < Path Margin ="48,50.992,139,-6.008" Fill ="SkyBlue"

           Stretch ="Fill" Stroke ="Navy"

           Data ="F1 M0.5,0.5 L71.5,0.5 L71.5,71.500367 L0.5,71.500367 z M24.5,13.508 L95.5,13.508 L95.5,84.508367 L24.5,84.508367 z M0.5,72.500366 L24.5,85.508366 M72.5,0.5 L96.5,13.508 M0.5,0.5 L24.5,13.508"/>

        </ BlockUIContainer >

 

FlowDocContent05

Looking at the Data property, you’ll understand that the only realistic way to create shapes like this is to use Expression Blend or Expression Design and import the XAML.

Shapes Inline

Shapes inline work in the same way as images:  

 

        < Paragraph FontSize ="14" TextAlignment ="Left"> Be sure to look out for our

          < Span Foreground ="Red" FontStyle ="Italic" FontWeight ="Heavy"> half price </ Span > Special Offer Items that are marked with a blue circle

          < InlineUIContainer BaselineAlignment ="Baseline">

            < Ellipse Width ="10" Height ="10" Fill ="Blue" />

          </ InlineUIContainer >

          .

        </ Paragraph >

        < Paragraph FontSize ="14" TextAlignment ="Left">

          You can also get 10% off items that are marked with a red square.

          < InlineUIContainer >

            < Rectangle Width ="10" Height ="10" Fill ="Red"/>

          </ InlineUIContainer > .

        </ Paragraph >

 

FlowDocContent06

 

Tables

By default, the content of the FlowDocument will be added vertically.   You can see this from the code snippet I used above for the two paragraphs.   When you need to have more than one element lined up horizontally, you have some choices.  One way is to use a Table.  The syntax for a table is verbose, but very logical.  You simply build it up by adding columns and groups of rows within each column.  Each row can then be split into cells and you can insert content into the individual cells.

Here’s a simple Table that uses two columns and three rows:

FlowDocContent07

The markup for this is:

    1          < Table >

    2            <!-- Create explicit columns> -->

    3            < Table.Columns >

    4              < TableColumn Width ="4*"/>

    5              < TableColumn Width ="8*" />

    6            </ Table.Columns >

    7            < TableRowGroup >

    8              < TableRow >

    9                < TableCell >

   10                  < Paragraph Margin ="5"> Bing Logo </ Paragraph >

   11                </ TableCell >

   12                < TableCell >

   13  

   14                    < BlockUIContainer Margin ="5" >

   15                    < Image Margin ="2,0" Width ="70" Source ="bingLogo.jpg" ></ Image >

   16                  </ BlockUIContainer >

   17  

   18                </ TableCell >

   19              </ TableRow >

   20              < TableRow >

   21                < TableCell >

   22                  < Paragraph Margin ="5,10,5,5"> Google Logo </ Paragraph >

   23                </ TableCell >

   24                < TableCell >

   25                  < BlockUIContainer Margin ="5" >

   26                    < Image Margin ="2,0" Width ="70" Source ="googleLogo.jpg" ></ Image >

   27                  </ BlockUIContainer >

   28                </ TableCell >

   29              </ TableRow >

   30              < TableRow >

   31                < TableCell >

   32                  < Paragraph Margin ="5,10,5,5"> Japanese Logo </ Paragraph >

   33                </ TableCell >

   34                < TableCell >

   35                  < BlockUIContainer Margin ="5" >

   36                    < Image Margin ="2,0" Width ="70" Source ="cr2.gif" ></ Image >

   37                  </ BlockUIContainer >

   38                </ TableCell >

   39              </ TableRow >

   40            </ TableRowGroup >

   41          </ Table >

 

Don’t be put off by the length of this markup.  It really is very simple, just very repetitive.

  • Line 1 starts the creation of the Table.
  • Lines 3 to 6 declare the two Columns and set the widths.
  • Line 7 starts the creation of a group of rows.  There are 3 rows in total in the TableRowGroup.
  • Line 8 starts the creation of the first row.
  • Within that row, Line 9 creates the first cell in that first row.
  • Line 10 contains the content of the first cell in the first row.
  • Line 12 starts a second cell which is in line with the first cell horizontally.
  • Lines 14 to 16 create the content for that second cell.
  • Line 19 closes the first row.

The rest of the markup simply repeats the same logic in order to create the remaining content in the same way.

(It would actually be possible to create the effect shown above using BlockUIContainers in line with Paragraphs.  The problem with that approach is that the markup soon becomes much harder to read and is also harder to write.  Editing the table, because of the structure of its syntax, is also much easier.)

As you will see in my next blog, you can use anchored blocks as another way of mixing text and images.


Posted Mar 22 2010, 02:10 PM by Ged Mead Filed under: XAML , WPF , Visual Basic.NET , Visual Basic , Visual Basic WPF , FlowDocument

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值