当前位置: 代码迷 >> 综合 >> WPF FlowDocuments (1) – Images, Shapes and Tables
  详细解决方案

WPF FlowDocuments (1) – Images, Shapes and Tables

热度:53   发布时间:2024-01-10 10:47:11.0

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:

 

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:

 

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

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

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 >

 

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 >

 

 

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:

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

  相关解决方案