How do ranges and selections work?
If you insert something at the top of the page through a range, is that overridden by inserting something with selection? Does selection affect ranges?
I'm having a problem where I do inserts in this order, but the InlineShapes show up at the top of the document above the Range.Inserts. Also, the Selection.InsertBefore gets replaced by the InlineShapes.
I would like my range insert to appear above each picture, like a heading. How can this be done?
Selection.InsertBefore
**Loop**
Range.InsertParagraphAfter
Selection.InlineShapes.AddPicture
**End Loop**
I've asked a question like this three times now with no responses. Anything would help!
EDIT:
I'm a step closer. Now, when I add my InlineShapes, I use Content.InlineShapes.AddPicture(FileName: x, range: y). Now the pictures are showing up in between paragraphs, but they are in the first cell of a table I add to the document before adding the picture. I add the table with with a collapsed range.
You write:
I've asked a question like this three times now with no responses. Anything would help!
And for reference, the questions referred to (I guess) are:
How to add items one at a time to to a new line a word document using word interop
Using interop.word ranges
... which all now have been answered :)
You ask multiple questions in this post however - first:
How do ranges and selections work?
Actually, the documentation covers this quite well:
A range:
"Represents a contiguous area in a document.
Each Range object is
defined by a starting and ending character position. Similar to the
way bookmarks are used in a document, Range objects are used to
identify specific portions of a document..."
Reference: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.word.range(v=office.14).aspx.
If you insert something at the top of the page through a range, is
that overridden by inserting something with selection?
It can be. This depends on what has been selected. If you select something that intersects with the range of the content you just inserted and changes the content, then you will make changes to the content of the range.
To understand this completely, I will recommend that you read about:
The Selection Interface
The Range Interface
Does selection affect ranges?
It depends. The documentation states:
Range objects are independent of the selection.
Reference: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.word.range(v=office.14).aspx
... so if you just do a simple selection in order to, e.g., read content or copy content to
the clipboard, nothing would change. However, if you use the selection to change content, of course this would affect the content pointed to by the ranges. In continuation of this you should note that MS recommends using Range objects for document manipulation:
Because Range objects share many of the same methods and properties as
Selection objects, using Range objects is preferable for manipulating
a document when there isn't a reason to physically change the current
selection.
Reference: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.word.selection.aspx
And finally, you ask:
I'm having a problem where I do inserts in this order, but the
InlineShapes show up at the top of the document above the
Range.Inserts. Also, the Selection.InsertBefore gets replaced by the
InlineShapes.
I would like my range insert to appear above each picture, like a
heading. How can this be done?
See my previous answer to your question: " How to add items one at a time to to a new line a word document using word interop " here: https://stackoverflow.com/a/12751805/700926 - that gives you a complete answer.
Related
I've been playing around with this, but I just can't get it to work. I have a table in Microsoft Word, and in this table is a mailmerge field which my C# program selects.
I'd like to delete the row which contains the field. I tried this:
app.Selection.SelectRow();
app.Selection.Delete();
Where app is an instance Microsoft.Office.Interop.Word.Application.
As written, this code deletes the text inside the table, but leaves an empty table row behind. How can I delete the table row itself?
When you have a Range or Selection, in most cases you can address the "containing" level like this:
app.Selection.Rows[1]
(Since I'm on a mobile device I can't check whether you can use .Delete() directly or whether you need .Range.Delete())
Similarly, Selection.Tables[1] would pick up the table around the selection and Selection.Paragraphs[1] the paragraph around the selection.
Note that, unless what you want to do simply won't work any other way, you should use the Range object. There will be less screen-flicker, execution will be faster and your code more predictable.
I stated the question above the way I did, because I can already do the following, and it doesn't give me the solution I need.
I can:
Get the number of pages per sheet
Get the last USED row on any given SHEET (not per printed page, so that doesn't help)
I can find out if manual or automatic page breaks have been inserted
(just not WHERE)
And that's what I need: To know the number of the row for each page break on any given sheet. Some sheets have 1 page, some have 100.
I need to do this because I need to put something at the bottom of each page, however, the number of pages per sheet is not static. Some sheets have been set to landscape, others to portrait. Some sheets have the "Put all columns on one page" option set, which CHANGES the number of rows on that page.
PLEASE NOTE: The solution to this problem is not "Use the footer", as the footer will not accept the data that I need to put on each page.
I also cannot statically decide the number of rows each page type might have -- I let Excel decide that when I set the orientation.
I've been looking for several days now, and I have been unable to find how to determine what the last row on a printed page will be.
I'm using office and VS 2010 and I'm using the office interop. I'm not posting much code because I have no idea what to use at this point. However, it is safe to say that to access any given worksheet I'm using the following code:
Excel.Application excelApp = new Excel.Application();
Excel.Worksheet workSheet;
I'd be willing to bet that there's a very simple way to do this, and I just haven't hit across the right combination of google search terms. But it's been a few days now, so I thought I'd post something here. Thanks for any help.
I don't think you have a way to calculate that on your own... It is very complicated, because the number of rows on each page depends on many variables (Printer page size, orientation, zoom level, etc.).
You can try to use this: Repeat specific rows or columns on every printed page
Given a data set containing multiple rows, from within a .NET console application I need to generate a report on a single page for each row, sending those pages directly to the printer.
I am attempting to use Microsoft Report for this by attaching it to a data set and placing TextBoxes where I wish. Generating the report and sending it to the printer are not a problem. Unfortunately, the data only seems to be available in aggregates -- First, Sum, Last, Max, etc. I cannot latch the text box to a bare field.
Some poking around here and other sites seems to address this, but only when the data is presented in a table. One post even said without elaboration, "My mistake was using Text Boxes"
Am I using the wrong tool for what I am attempting to accomplish?
I ran into the same problem and managed to solve it. The solution seems a little convoluted to me so don't quote me on the "right" way to do this, but here is what I did:
Make sure you have a Dataset defined for your report.
Add a "Table" control to the report. This seems to be needed in order to iterate the rows in your Dataset.
Delete the header row and two of the default columns from the table so that you are left with a single row with a single column.
Expand the table to the width of your layout and make it as tall as you will need for your "free form" layout.
By default, there is a TextBox inside the table cell. Right-click the empty table cell and choose "delete" to remove that TextBox.
Drag a "Rectangle" control into the empty table cell. It seems to automatically "dock" to the width/height of the table cell.
Now you should be able to drag the fields from your DataSet (TextBoxes, etc) into the Rectangle to produce the desired layout.
Note that I am in the early stages of using this approach so I'm not sure if I am going to hit any walls... but for a basic report that uses TextBoxes and a page break after each "row" it seems to be working ok.
Or you try to use a list.
In the list you can arange textboxes (and other controls) as you want and they will be filled for each record in the recordset.
This work for me. :-)
I'm using a GridView that is bound to an object (an entity). The grid can be filtered and otherwise customized in terms of the data it shows. The rows, columns and more specifically cells will be formatted using some rules, but also from the user specifically setting formatting options.
My questions is about the best way to recall the chosen formatting for specific cells. Currently my best method is to store an id for each cell that looks up all of the formatting for that cell (i.e. ForeColor, BackColor, FontWeight etc).
Another way would be to create a new table (called say Formatted_Cells) that stores the id and column name of the table in question, and then the formatting options. This would involve checking the Formatted_Cells table each time a cell is processed to check for formatting. It is quite a bit of processing (similar to the above method). If I did this I could flag any rows that have custom formatting, and if they do not I wouldn't need to check the Formatted_Cells table which does provide an advantage over remembering formatting for EVERY cell, when the vast majority will not have any custom formatting.
Is there a better way? I don't think I can use Serialization to help as the grid is loaded from the database which may be modified elsewhere. But perhaps I'm missing something obvious?
Much appreciated.
I'd suggest an additional table also.
Two possible solutions come to mind:
1- Do the formatting in two passes. First load the grid normally, then read Formatted_Cells table from database, find styled rows in grid and apply special styling.
2- When quering database for Cells, add Formatted_Cells table with left join. When loading grid, check for additional columns that might come from left join, apply those. If no additional columns, style normally.
I am developing application in C# Windows Forms, i make crystal reports on the basis of data collection list in c#, for example i have a table having EmpID, Name, Sponsor, Job Title, Nationality etc. I bring them in collection in c# and pass it to crystal report, where i see my attributes in Database fields, if i drag and drop those fields on the report, for example Name, Job Title, Nationality, then i can see their columns coming in Details section, but the issue is, i have about 25 attributes and i have made a check list of 25 attributes in c#, if i check 13 attributes, it should make a report of 13 columns, the problem is, we make report in crystal report on the basis of drag and dropping fields, how can i dynamically do this, means if there are 13 fields selected in c# check list, there should be just 13 columns in report. Please find the image attached, "How currently i am doing" Please zoom it by right click on it, and open in new window.
I think that the easiest way to approach this, considering data type representations and all of the Crystal complexity under the covers, is to layout your report with all 25 fields sized appropriately.
Then, at runtime, you will need to reposition the report objects, which could be a little tricky due to the relatively unstructured way in which crystal provides the information.
The way I would approach this is to loop through the report objects and generate one SortedList for the data fields and one SortedList for the header fields. They should be sorted on their Left position so that you can process them in appearance order.
Once you have the sorted lists of objects, you can cycle through each one and, if it was not selected by the user, set the Width to 0.
As you are moving through the fields, you will keep track of the current left position. The first field that you process will set your starting point, even if it is not visible. Then, for all subsequent fields, if the field is visible, you will set its left value to the current left position, then add its width plus some separator space to the current left position for the next field.
Hopefully this will help you solve your problem.
It sounds like this would be a good place for a cross-tab report. In this case you'd need to add a cross tab to your report header or footer and pass your data into the report with a column for each attribute descriptions and then group on the attribute description. See below for details:
Data:
RowID ColDesc ColValue
1 Attr1 Value1
1 Attr2 Value2
2 Attr1 Value3
Then you can add your crosstab where your row field is RowID, your column field is ColDesc and the field to summarize is ColValue. You can use a Max of summary on the summarized field since it is different.
This is untested, but I believe that the output for this should be:
CrossTab:
Attr1 Attr2
1 Value1 Value2
2 Value3
As you can see that as you add a new attribute it will show up as a new column in the crosstab. As I said previously, this is untested so I apologize for any errors, but I hope it is enough to help you out. Thanks
Give a look at these links
http://www.c-sharpcorner.com/UploadFile/uditsingh/CR1111022006055359AM/CR11.aspx
http://www.crystalkeen.com/articles/crystalreports/dynamiccrosstab.htm
Using this Google Search
Crystal Reports will not automatically add columns & headers to a report given a list of fields.
My recommendation is to use the Report Application Server .NET SDK to dynamically alter a report. The link includes the API reference, as well as samples.