现在的位置: 首页 > 综合 > 正文

WPF FlowDocuments (1) – Images, Shapes and Tables

2014年01月26日 ⁄ 综合 ⁄ 共 7312字 ⁄ 字号 评论关闭

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:
,
,
,
,
,

抱歉!评论已关闭.