views:

635

answers:

3

I've got a SQL Reporting Services 2005 report that includes a textbox on the first page. The string input for the textbox can be very large and include newlines. The textbox size is fixed and another textbox is included on the second page of the report to handle any spillover text that didn't fit in the first page's textbox. If the second page textbox becomes full, then I would like to include a "..." at the end of the text to show that some text was cut off.

I've tried using the TextRenderer.MeasureText() method but it appears to only work on single lines. I'm trying the following code

string str = string.Copy(commentString);
TextFormatFlags flags = TextFormatFlags.WordBreak |
                        TextFormatFlags.WordEllipsis |
                        TextFormatFlags.ModifyString;
float textBoxWidthInches = 3.8f;
float textBoxHeightInches = 3.4f;
Size size = new Size(
    (int)(textBoxWidthInches * 72 - 2),
    (int)(textBoxHeightInches * 72 - 2));
TextRenderer.MeasureText(str, new Font("Arial", 8), size, flags);

I then expect the str to include a '\0' at the point where I need to break my string, however, it isn't showing up. If I remove the WordBreak flag and input a string with a long first line, it does include the '\0' at the correct spot for the first line, but it is only working for a single line.

My questions are:

1) How do I "continue" text from one textbox to another in Sql Reporting Services 2005?

2) If not, how can I calculate where I need to break my string up so that it fits inside a textbox?

3) Optionally I'd like to include a "..." at the end of the second textbox for text that is longer than both textboxes can fit.

Edit: What I'm trying to accomplish is something like this:

|------------------------|
|                        |
|     Header Page 1      |
|------------------------|
|        |               |
|        |               |
|TextBox1|               |
|        |               |
|--------|               |
|                        |
| Other Data             |
|                        |
|                        |
|                        |
|                        |
|                        |
|                        |
|                        |
|------------------------|


|------------------------|
|                        |
|     Header Page 2      |
|------------------------|
|        |               |
|        |               |
|TextBox2|               |
|        |               |
|--------|               |
|                        |
| Other Data             |
|                        |
|                        |
|                        |
|                        |
|                        |
|                        |
|                        |
|------------------------|

I then want TextBox1 to continue to TextBox2 on the second page. Using the CanGrow attribute will not get the desired behavior.

A: 

When CanGrow is set the text box will split over more than one page once the height is larger than a page. eg. The textbox will move to a second page first if it shares a page with another control. See here.

If you have to cut the textbox off at two pages you could set the textbox size to 2 pages, then set CanGrow to false and CanShrink to true. This way the textbox would always be smaller than 2 pages.

Then test the number of lines in your text (You may have to write a function to do this) versus the lines you know can fit in in the textbox to control the visibility of another textbox containing the message "Further text truncated".

jimconstable
Thanks for the answer, but I've tried everyway I can think of using the CanGrow and CanShrink and cannot get the desired behavior. I edited my post to give an example of the desired output.
Ezweb
A: 

You can also approximate this behaviour by using a table, groupings and breaking after each group. So page 1 would be the first value of group1 and page 2 would be the second value of group1, etc.

The detail group would be the content of the page (or you could add more groupings if you like)

Zaid Zawaideh
A: 

Here is what I ended up with:

  public static IList<string> WordWrap(
     string text,
     Font printFont,
     Graphics graphics,
     IList<SizeF> sizeF,
     string tooLongText)
  {
     List<string> list = new List<string>();
     int charsFit;
     int linesFilled;

     foreach (SizeF size in sizeF)
     {

        graphics.MeasureString(
           text,
           printFont,
           size,
           new StringFormat(),
           out charsFit,
           out linesFilled);

        char[] whitespace = new[] { ' ', '\t', '\r', '\n' };
        int index = charsFit;

        if (text.Length > charsFit)
           index = text.LastIndexOfAny(whitespace, charsFit);

        if (index < 0) index = charsFit;

        string rv = text.Substring(0, index).Trim();
        text = text.Substring(index).Trim();
        list.Add(rv);
     }

     if (!string.IsNullOrEmpty(text))
     {
        string lastText = list[list.Count - 1];
        SizeF size = sizeF[sizeF.Count - 1];
        charsFit = 0;
        string newLastText = lastText + Environment.NewLine + tooLongText;
        while (charsFit < newLastText.Length)
        {
           graphics.MeasureString(
              newLastText,
              printFont,
              size,
              new StringFormat(),
              out charsFit,
              out linesFilled);
           lastText = lastText.Substring(0, lastText.Length - 1);
           newLastText = lastText + Environment.NewLine + tooLongText;
        }

        list.RemoveAt(list.Count - 1);
        list.Add(newLastText);
     }

     return list;
  }

I then generate two public string properties for my two textboxes. If this function returns a list with count > 0, first textbox value = list[0]. If list count > 1, second textbox value = list[1]. Not the best code I'm sure, but it worked for my needs.

Ezweb