I have a datagrid that I want to be able to copy and paste to/from excel. Pretty common scenario. I have the copy and paste functions implemented. However, this application has several datagrids, and I'd like to prevent the user from trying to copy data from one grid to another since the data is different.
I can serialize the objects in these grids to any format I want, so adding some kind of metadata that says "This data only goes in that grid" is trivial. But I can't add the metadata because then it would show up in excel. Is there some solution to this problem that allows me to paste data in one format in my application, but that excel will still handle correctly?
If you look at the clipboard class you can set the text but there is also quite a bit more you can do with it. Most of the advanced things you will want to do with the clipboard revolve around a pair of routines "SetDataObject" and "GetDataObject". To use this with multiple formats you can specify:
var serializableObject = new MyObject();
var clipData = new DataObject();
clipData.SetData(DataFormats.Text, "abcdefg");
clipData.SetData("CustomFormat", serializableObject);
Clipboard.SetDataObject(data);
Once you have done this you can get the data back from the clipboard by reversing this and requesting the data from the custom format. Briefly the reverse call looks like:
var clipData = (DataObject)Clipboard.GetDataObject();
var myObject = clipData.GetData("CustomFormat") as MyObject;
For a more complete example from Microsoft, see this page: http://msdn.microsoft.com/en-us/library/637ys738(v=vs.110).aspx. Just look at the bottom where it explains the use of multiple formats.
Hope this helps. Best of luck!
Related
I'm trying to create a validation tool using the iText7, to compare the reading order and tagging order from the tagged PDF. Im new to iText.
I have used the below code in c# to extract the tagging structure and save it as xml.
Ref: (Get marked content using the MCID content)
FileStream outXml = new FileStream("pdf_content.xml",FileMode.CreateNew);
TaggedPdfReaderTool tool = new TaggedPdfReaderTool(pdfoc);
tool.SetRootTag("root");
tool.ConvertToXml(outXml);
outXml.Close();
I expect to export the reading order to Xml or other format.
No.
Reading order is a human concept, and might be different from person to person.
Have a look at the following example:
The red parts are snippets that are relevant to the story, but they break the normal layout.
Do you read them first?
Do you read them as you are passing them in top to bottom, left-to-right reading order?
Do you read them last?
Reading order (in the general case) needs human verification at least.
I've been developing a Word-AddIn (Office 365 version 1706, Windows 10) which basically stores data in charts so they could be fed updated data from our servelets and ultimately the chart updates itself with all the data it needs.
This works perfectly fine EXCEPT when I alter the layout options for a chart from the default "In Line with Text" to "With Text Wrapping" to have multiple charts next to each other for example.
How this works, as long as you don't alter the layout options, is by accessing the Microsoft.Office.Interop.Word.Application COM object, which has a Selection object, which furthermore has InlineShapes, is like so:
var inlineShapes = Application.Selection.InlineShapes;
if(inlineShapes > 0)
{
for(var i = 1; i < inlineShapes.Count + 1; i++)
{
if (inlShape.HasChart == MsoTriState.msoTrue)
return new WordChart(inlShape);
}
}
For sake of simplicity I spared you the whole ordeal of dealing with COM objects.
Again, this works if you don't tamper with the layout options of the chart, but as soon as the layout has been altered to say "Behind Text" I can't find that chart in any InlineShape.
Has anyone experienced this before?
I've combed through the Application.Selection object and couldn't find anything.
However the InlineShape is still in the Application.InlineShapes object itself, but how would I know which one is to be selected?
I would really appreciate ANY input, because as of now I have no idea on what to do anymore.
Ok, I finally found those little charts!
This Stackoverflow post helped me:
How to check which shapes/objects are selected/active?
More details to what solved my problem:
Once I changed the the layout options (see original question) I wouldn't be able to find Charts as InlineShapes anymore.
Instead they would be listed under Selection.ShapeRange.get_Item(i) (I checked for Shapes/InlineShapes, so I didn't see items as what a chart could be).
Now you could either convert them to InlineShapes, which does exactly that, in Word as well, which you don't want, or convert that Shape to your VSTO.WordChart, which I did.
(This question was formerly titled "C# / WPF : Going from Excel Interop "Range" to WPF "FlowDocument"" however I've made progress on that front that allows me to restrict my question. I'm leaving the original question below so existing answers will still make sense.)
I'm using Office Interop to read the contents of cells in an Excel worksheet. Some of those cells contain Rich Text (for example some words are italicized but not the whole cell) and I would like to capture them as RTF so I can then display them into WPF controls.
I have been able to obtain the RTF contents of cells using the clipboard API, where I use Excel Interop to copy a Range of one cell to the clipboard, and then read the clipboard, like so:
// Step 1 : retrieve the RTF from the clipboard as a string
string txt = Clipboard.GetText(TextDataFormat.Rtf);
// Step 2 : create a FlowDocument object and a TextRange object:
FlowDocument doc = new FlowDocument();
TextRange tr = new TextRange(doc.ContentStart, doc.ContentEnd);
// Step 3 : convert the clipboard string to a stream
byte[] byteArray = Encoding.ASCII.GetBytes(txt);
MemoryStream stream = new MemoryStream(byteArray);
// Step 4 : load that stream into TextRange
tr.Load(stream, DataFormats.Rtf);
If I then assign "doc" to the Document property of, say, a RichTextBox control, it'll display the content of the Excel cell with the exact same formatting as Excel does, down to colored words and font sizes.
However, this is extremely slow. It may take minutes to load a thousand cells that way, even if most are empty.
So here's my updated question : clearly Excel has a mechanism for returning the RTF content of an Excel cell, otherwise my Clipboard code couldn't work. But is there are more efficient way than the Clipboard to exploit that mechanism ? Ideally through Interop ?
Original question :
This may be an unusual question but as I'm quite new to C#, WPF and Interop, I might be going about things the wrong way so don't hesitate to offer a better approach. Here's what I'm trying to do :
I'm coding a WPF application that uses Office Interop to grab the contents of cells from an Excel worksheet. That content is text which may contain some formatting (for example some words are in bold, others are in italics). The application then displays that content in a "FlowDocumentScrollViewer" control on its GUI.
I want this "FlowDocumentScrollViewer" control to render the content from the Excel cell exactly as it appears in Excel, with formatting and everything.
The best I've managed so far is to display the cell's content without any formatting. Here's how this works : I use Office Interop to read a Range of cells from the worksheet and take their Value2 property. Value2 is of type "object". Then I create a FlowDocument object out of it, like so:
FlowDocument doc = new FlowDocument();
Paragraph p = new Paragraph(new Run(Variable_containing_a_Value2.ToString()));
doc.Blocks.Add(p);
And then I store this FlowDocument into the "FlowDocumentScrollViewer" Document property.
Now since I'm using "ToString()" on the Value2 I'm not surprised that any formatting information this object might contain disappears past this point.
My problem is, I haven't been able to find a way to create that FlowDocument, from that Value2 object, that preserves formatting.
Now, I know there has to be a way to get that information through, because when I copy my Excel cell and paste it in Word, for example, then the formatting is carried through. I just don't know how.
Help me Obiwans, you're my only hope, as even Google has failed me.
It seems to me that you have at least a couple of options that will work better than just copying the cell contents as text. The Range object has Copy() and CopyPicture() methods, which you can use to have Excel copy the contents of the range to the clipboard.
The basic Copy() method should (I haven't tested it) put the contents of the cell into the clipboard in a variety of formats, including RTF. And you should be able to get the RTF and put that into the FlowDocument element.
Using RTF, you may still not get exactly the representation as seen in Excel. The only way to do that is to have Excel do the rendering. In that case, you'll want the CopyPicture() method, which will put picture of the range on the clipboard. This will be either a bitmap or metafile, depending on the options you use for the method call. You can then retrieve these from the clipboard and put them into your FlowDocument.
Depending on what applications you're looking at, e.g. Word, there's yet another more complicated approach, one that I doubt would work with FlowDocument, but which they are using. That is, they are presenting the Excel range an OLE object. This is harder to implement, but has the advantage that it's a live representation of the original Excel document, and the user can edit the range in-place in the host application.
The above should be enough to get you pointed in the right direction, so at least you know what you're looking for when you do your web searches. As stated, your question is very broad, and so the above is necessarily vague as well. Once you've decided on a particular method, have done some research and made an attempt into implementing that method, if you still have problems you can post a new question, with a good Minimal, Complete, and Verifiable code example that shows clearly what you've tried, with a detailed explanation of what specifically you're still having trouble with.
I'm starting with C# again after 3 years (have average experience with object orientated languages; here I'm mainly missing function names). I'm not too sure it's possible in c#, so if you can recommend another language I will try to look there.
My Question(s):
On program start (or button) I want to extract a part of a Website and save it (temporary of file don't matter). That way I wont need to buffer/load (loadtime) anything again and can access the content if I go offline afterward.
I want to extract some numbers out of the content and do simple math with them.
Would be great to know if its possible and how. I'm happy if you can tell me the main functions I should look into. Some basic code would be great too if its not too much to ask.
If you want to have access to the information even if your program closes/restarts then you will need to export the source code to a file as follows:
using (WebClient wb = new WebClient())
{
string source = wb.DownloadString("http://example.com");
File.WriteAllText("c:\\exampleFile.txt", source);
}
Otherwise you can remove the File.WriteAllText("c:\\exampleFile.txt", source); and simply parse the parts you want from the source and do your calculations.
Keep in mind this will download the source code of the url as 'it is' that means you will need to do some parsing of the text in order to get the information you want out of it.
May be you are looking for this:
var contents = new System.Net.WebClient().DownloadString(url);
I have data in an Excel spreadsheet with values like this:
0.69491375
0.31220394
The cells are formatted as Percentage, and set to display two decimal places. So they appear in Excel as:
69.49%
31.22%
I have a C# program that parses this data off the Clipboard.
var dataObj = Clipboard.GetDataObject();
var format = DataFormats.CommaSeparatedValue;
if (dataObj != null && dataObj.GetDataPresent(format))
{
var csvData = dataObj.GetData(format);
// do something
}
The problem is that csvData contains the display values from Excel, i.e. '69.49%' and '31.22%'. It does not contain the full precision of the extra decimal places.
I have tried using the various different DataFormats values, but the data only ever contains the display value from Excel, e.g.:
DataFormats.Dif
DataFormats.Rtf
DataFormats.UnicodeText
etc.
As a test, I installed LibreOffice Calc and copy/pasted the same cells from Excel into Calc. Calc retains the full precision of the raw data.
So clearly Excel puts this data somewhere that other programs can access. How can I access it from my C# application?
Edit - Next steps.
I've downloaded the LibreOffice Calc source code and will have a poke around to see if I can find out how they get the full context of the copied data from Excel.
I also did a GetFormats() call on the data object returned from the clipboard and got a list of 24 different data formats, some of which are not in the DataFormats enum. These include formats like Biff12, Biff8, Biff5, Format129 among other formats that are unfamiliar to me, so I'll investigate these and respond if I make any discoveries...
Also not a complete answer either, but some further insights into the problem:
When you copy a single Excel cell then what will end up in the clipboard is a complete Excel workbook which contains a single spreadsheet which in turn contains a single cell:
var dataObject = Clipboard.GetDataObject();
var mstream = (MemoryStream)dataObject.GetData("XML Spreadsheet");
// Note: For some reason we need to ignore the last byte otherwise
// an exception will occur...
mstream.SetLength(mstream.Length - 1);
var xml = XElement.Load(mstream);
Now, when you dump the content of the XElement to the console you can see that you indeed get a complete Excel Workbook. Also the "XML Spreadsheet" format contains the internal representation of the numbers stored in the cell. So I guess you could use Linq-To-Xml or similar to fetch the data you need:
XNamespace ssNs = "urn:schemas-microsoft-com:office:spreadsheet";
var numbers = xml.Descendants(ssNs + "Data").
Where(e => (string)e.Attribute(ssNs + "Type") == "Number").
Select(e => (double)e);
I've also tried to read the Biff formats using the Excel Data Reader however the resulting DataSets always came out empty...
The BIFF formats are an open specification by Microsoft. (Note, that I say specification not standard). Give a read to this to get an idea of what is going on.
Then those BIFF you see correspond to the some Excel formats. BIFF5 is XLS from Excel 5.0 and 95, BIFF8 is XLS from Excel 97 to 2003, BIFF12 is XLSB from Excel 2003, note that Excel 2007 can also produce them (I guess Excel 2010 too). There is some documentation here and also here (From OpenOffice) that may help you make sense of the binary there...
Anyways, there is some work has been done in past to parse this documents in C++, Java, VB and for your taste in C#. For example this BIFF12 Reader, the project NExcel, and ExcelLibrary to cite a few.
In particular NExcel will let you pass an stream which you can create from the clipboard data and then query NExcel to get the data. If you are going to take the source code then I think ExcelLibrary is much more readable.
You can get the stream like this:
var dataobject = System.Windows.Forms.Clipboard.GetDataObject();
var stream = (System.IO.Stream)dataobject.GetData(format);
And read form the stream with NExcel would be something like this:
var wb = getWorkbook(stream);
var sheet = wb.Sheets[0];
var somedata = sheet.getCell(0, 0).Contents;
I guess the actual Office libraries from Microsoft would work too.
I know this is not the whole tale, please share how is it going. Will try it if I get a chance.