I have a C#/WPF application that allows the user to export information into a Word document. At the moment it works - and creates the document as expected - however the UI locks and the moment I try to thread this method I get varying errors.
The document creation takes in a list of custom items, then builds sections in the Word document based on each item. It creates a table for each image, and in those tables I insert an image placeholder. Once this is done I traverse the document and replace the placeholders with their associated image.
I believe the threading issue is due to the way images are inserted into the document - utilising Clipboard.Clear() and Clipboard.SetDataObject(img).
Is there a cleaner way for me to insert JPG's from disk into the document, or is there a nice way to thread such a method? Here is the offending method:
private static void InsertImagesTables(string document, List<Record> allRecords)
{
Document oDoc = oWord.Documents.Open(document);
Object oMissing = Missing.Value;
object NormalStyle = "Normal";
oWord.Visible = false;
foreach (Record record in allRecords)
{
foreach (RecordImage rImage in record.Images)
{
//insert over placeholder
var range = oDoc.Content;
if (range.Find.Execute("[[" + record.Title + rImage.ImagePath + "]]"))
{
try
{
//insert the image
var prevRange = range.Previous(WdUnits.wdCharacter);
Table imageTable;
imageTable = oDoc.Tables.Add(range, 1, 1, ref oMissing, ref oMissing);
imageTable.Borders.InsideLineStyle = WdLineStyle.wdLineStyleNone;
imageTable.Borders.OutsideLineStyle = WdLineStyle.wdLineStyleNone;
Image img = Image.FromFile(rImage.ImagePath + ".jpg");
Clipboard.Clear();
Clipboard.SetDataObject(img);
imageTable.Cell(1, 1).Range.Paste();
imageTable.Cell(1, 1).Range.set_Style(ref NormalStyle);
imageTable.Cell(1, 1).Range.ParagraphFormat.Alignment = WdParagraphAlignment.wdAlignParagraphCenter;
InlineShape inlineShape = imageTable.Cell(1, 1).Range.InlineShapes[1];
imageTable.Rows.Alignment = WdRowAlignment.wdAlignRowCenter;
string caption = rImage.Caption;
inlineShape.Range.InsertCaption(Label: "Figure", Title: " - " + caption, Position: WdCaptionPosition.wdCaptionPositionBelow);
range.Expand(WdUnits.wdParagraph);
}
catch // no image for record - do nothing
{ }
}
}
}
oDoc.Close(true);
}
I've tried BackgroundWorkers, Dispatchers, async Tasks and Threads (with and without ApartmentState.STA) with varying outcomes. Most just raise an error, but a few run and complete, without placing every image in the document - such as the STA approach.
Any help here is much appreciated,
Mike
Fixed. Thanks vernou for taking the time. I solved it by removing the Clipboard interaction and instead, properly utilising Word interop with a backgroundworker:
Range cellRange = imageTable.Cell(1, 1).Range;
cellRange.InlineShapes.AddPicture(rImage.ImagePath + ".jpg", ref oMissing, ref oMissing, ref oMissing);
instead of:
Clipboard.Clear();
Clipboard.SetDataObject(img);
imageTable.Cell(1, 1).Range.Paste();