How to change text field in a PPT programmatically in C#? - c#

I have a PPT template in which I need to programmatically replace some text fields with data that comes from my database then convert the ppt to pdf and send it as attachment in an email. I am not sure of how to change the content of text fields in the PowerPoint Presentation. I think OpenXML needs to be used.
Please help me to feed dynamic data into my ppt template.

I have worked previously with the DocumentFormat.OpenXml from Microsoft but with word files. I played a bit with it to replace some Texts in a Power Point file.
Here is my simple test code snippet:
static void Main(string[] args)
{
// just gets me the current location of the assembly to get a full path
string fileName = GetFilePath("Resource\\Template.pptx");
// open the presentation in edit mode -> the bool parameter stands for 'isEditable'
using (PresentationDocument document = PresentationDocument.Open(fileName, true))
{
// going through the slides of the presentation
foreach (SlidePart slidePart in document.PresentationPart.SlideParts)
{
// searching for a text with the placeholder i want to replace
DocumentFormat.OpenXml.Drawing.Text text =
slidePart.RootElement.Descendants<DocumentFormat.OpenXml.Drawing.Text>().FirstOrDefault(x => x.Text == "[[TITLE]]");
// change the text
if (text != null)
text.Text = "My new cool title";
// searching for the second text with the placeholder i want to replace
text =
slidePart.RootElement.Descendants<DocumentFormat.OpenXml.Drawing.Text>().FirstOrDefault(x => x.Text == "[[SUBTITLE]]");
// change the text
if (text != null)
text.Text = "My new cool sub-title";
}
document.Save();
}
}
In my case i had a simple presentation with one slide and in the Text fields the entries "[[TITLE]]" and "[[SUBTITLE]]" which i replaced with this text.
For my test file this worked well but maybe you will need to adopt / change something for your specific file.
E.g. in Word i had sometimes texts which was splitted in multiple Text parts within a Run element and had to write a logic to "collect" this data and replace them with one Text element with the new text i wanted to be there or maybe you have to search for other Descendant types.

Related

Formatting Sections of a TextRange or TextRange2 in PowerPoint.Interop C#

I would like to add rich text to a TextBox on a PowerPoint Slide.
I am using .Net 4.7.2 with Microsoft.Office.Interop.PowerPoint
Overview
// Initialization of the Application
public PresentationGenerator () {
pptApplication = new Application ();
}
// Creating a new document based on a teplate.
Presentation pptPresentation = generator.pptApplication.Presentations.Open (templatePath, MsoTriState.msoFalse, MsoTriState.msoTrue, showWindow);
// Setting a slide and editing the text works perfectly fine with this
Slide currentSlide;
currentSlide = pptPresentation.Slides[1];
currentSlide.Shapes.Title.TextFrame.TextRange.Text = "Wonderful Title";
currentSlide.Shapes[3].TextFrame.TextRange.Text = "Great TextBox";
This is an mwe of my setup to set text on slides.
I would however like to add text to one of my shapes using a loop and setting the layout depending on a property.
Imagine the following Array
customParagraphs = [
{
text:"example heading",
type:"title"
},{
text:"example normal text",
type:"text"
}]
I can loop over this list and add the text to the end of the TextRange2 using .insertAfter(text) and try setting the font-size for the text portion that i added.
TextRange2 textrange = currentSlide.Shapes[3].TextFrame2.TextRange
foreach(var paragraph in customParagraphs){
TextRange2 paragraphRange = textrange.Paragraphs.insertAfter(paragraph.text)
if(paragraph.type == "title"){
paragraphRange.Font.Size = 24.0F;
}
}
This will successfully add the text and change the font-size, if type is title. However it will change the font-size for the whole text-range!
The reference returned by .insertAfter() seems to refer to the instance of TextRange2 and not my newly added paragraph.
My Questions
Is there a way to change the font-size and other attributes of a line, paragraph or word inside a TextRange or TextRange2 element?
Is there a better way to add text to a TextRange or TextRange2 element than .insertAfter that preferably returns a reference to only the text i added?

Store all information about the text of a richtextbox and reconstruct it- c# winforms

Is there a way to store all of the information about the text in a richtextbox (colors, sizes, fonts, etc) and reconstruct it in another richtextbox, which is not in the same form or project?
For example, I have a richtextbox which its text contains multiple fonts and colors, and some lines are centered, and I want to reconstruct it in another richtextbox.
I added that the new richtextbox is not in the same project, so i need to restore the information somewhere (for example, even in a string or a file).
To copy the text and formatting from one richTextBox to another, simply use:
richtextBox2.Rtf = richtextBox1.Rtf;
The Rtf property is simply a string, so you can do with it whatever you can do with strings.
You can do that with the following steps
assume we have two projects
the first is WinFormApp1 and the second is WinFormApp2
Save the RTF of the RichTextBox1 in WinFormApp1 in a text file
In WinFormApp1
const string path = #"D:\RichTextBox\Example.txt";
var rtbInfo = richTextBox1.Rtf;
if (!File.Exists(path))
{
File.Create(path);
TextWriter textWriter = new StreamWriter(path);
textWriter.WriteLine(rtbInfo);
textWriter.Close();
}
else if (File.Exists(path))
{
File.WriteAllText(path, rtbInfo);
}
Read the data from the text file and assigned to RTF of the RichTextBox1 in WinFormApp2
In WinFormApp2
private void Form1_Load(object sender, EventArgs e)
{
const string path = #"D:\RichTextBox\Example.txt";
if (File.Exists(path))
{
richTextBox1.Rtf = System.IO.File.ReadAllText(path);
}
}

Using user input numbers to find a word in a textbox

Currently trying to work out how I use user inputs. In my case it is 1/2/3 to find a specific line and word in a text box and copy that information and output the word into a new text box. The text box the user inputs into has already been split so the first number chooses the text file to choose a word from the second number chooses a line and the third number chooses a word. After the first number is read the chosen text file is going to be output into a rich text box before the keyword is discovered and output.
So far I don't have much code towards this but the only part I really don't understand is how to find the specific line and word. Currently the text box with the three user inputs is being broken up into each individual section and being stored in invisible labels for each section as you can see in my code.
Here's my code so far:
public partial class Form1 : Form
{
int NumLines;
public Form1()
{
InitializeComponent();
}
private void btnSubmit1_Click(object sender, EventArgs e)
{
var charArray = txtPoemInput.Text.Split('/'); // Dividing the users input into 3 usable sections using invisible labels
lblPoem.Text = charArray[0];
lblLine.Text = charArray[1];
lblWord.Text = charArray[2];
// Testing for which poem is going to be used
if (lblPoem.Text == "1")
{
//Read in text file
}
else if (lblPoem.Text == "2")
{
//Read in text file
}
else if (lblPoem.Text == "3")
{
//Read in text file
}
NumLines = txtPoem.Lines.Count();
// the user input line and word finds and selects the speciic word required
// Displays word in the Keyword box

How to replace some text with picture in RichTextBox without clipboard? [duplicate]

Most of the examples I see say to put it on the clipboard and use paste, but that doesn't seem to be very good because it overwrites the clipboard.
I did see one method that manually put the image into the RTF using a pinvoke to convert the image to a wmf. Is this the best way? Is there any more straightforward thing I can do?
The most straightforward way would be to modify the RTF code to insert the picture yourself.
In RTF, a picture is defined like this:
'{' \pict (brdr? & shading? & picttype & pictsize & metafileinfo?) data '}'
A question mark indicates the control word is optional.
"data" is simply the content of the file in hex format. If you want to use binary, use the \bin control word.
For instance:
{\pict\pngblip\picw10449\pich3280\picwgoal5924\pichgoal1860 hex data}
{\pict\pngblip\picw10449\pich3280\picwgoal5924\pichgoal1860\bin binary data}
\pict = starts a picture group,
\pngblip = png picture
\picwX = width of the picture (X is the pixel value)
\pichX = height of the picture
\picwgoalX = desired width of the picture in twips
So, to insert a picture, you just need to open your picture, convert the data to hex, load these data into a string and add the RTF codes around it to define a RTF picture. Now, you have a self contained string with picture data which you can insert in the RTF code of a document. Don't forget the closing "}"
Next, you get the RTF code from your RichTextBox (rtbBox.Rtf), insert the picture at the proper location, and set the code of rtbBox.Rtf
One issue you may run into is that .NET RTB does not have a very good support of the RTF standard.
I have just made a small application* which allows you to quickly test some RTF code inside a RTB and see how it handles it. You can download it here:
RTB tester (http://your-translations.com/toys).
You can paste some RTF content (from Word, for instance) into the left RTF box and click on the "Show RTF codes" to display the RTF codes in the right RTF box, or you can paste RTF code in the right RTB and click on "Apply RTF codes" to see the results on the left hand side.
You can of course edit the codes as you like, which makes it quite convenient for testing whether or not the RichTextBox supports the commands you need, or learn how to use the RTF control words.
You can download a full specification for RTF online.
NB It's just a little thing I slapped together in 5 minutes, so I didn't implement file open or save, drag and drop, or other civilized stuff.
I use the following code to first get the data from clipboard, save it in memory, set the image in clipboard, paste it in Rich Text Box and finally restore the data in Clipboard.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
OpenFileDialog1.Filter = "All files |*.*"
OpenFileDialog1.Multiselect = True
Dim orgdata = Clipboard.GetDataObject
If OpenFileDialog1.ShowDialog = Windows.Forms.DialogResult.OK Then
For Each fname As String In OpenFileDialog1.FileNames
Dim img As Image = Image.FromFile(fname)
Clipboard.SetImage(img)
RichTextBox1.Paste()
Next
End If
Clipboard.SetDataObject(orgdata)
End Sub
The OpenFileDailog1, RichTextBox1 and Button1 are Open File Dialog, Rich Text Box and button controls respectively.
private void toolStripButton1_Click(object sender, EventArgs e)
{
FileDialog fDialog = new OpenFileDialog();
fDialog.CheckFileExists = true;
fDialog.CheckPathExists = true;
fDialog.RestoreDirectory = true;
fDialog.Title = "Choose file to import";
if (fDialog.ShowDialog() == DialogResult.OK)
{
string lstrFile = fDialog.FileName;
Bitmap myBitmap = new Bitmap(lstrFile);
// Copy the bitmap to the clipboard.
Clipboard.SetDataObject(myBitmap);
DataFormats.Format format = DataFormats.GetFormat(DataFormats.Bitmap);
// After verifying that the data can be pasted, paste
if(top==true && this.rtTop.CanPaste(format))
{
rtTop.Paste(format);
}
if (btmLeft == true && this.rtBottomLeft.CanPaste(format))
{
rtBottomLeft.Paste(format);
}
if (btmCenter == true && this.rtBottomCenter.CanPaste(format))
{
rtBottomCenter.Paste(format);
}
if (btmRight == true && this.rtBottomRight.CanPaste(format))
{
rtBottomRight.Paste(format);
}
}
}
Here is what I do to hack the rich text control:
Insert the required image in wordpad or MS-WORD. Save the file as 'rtf'. Open the rtf file in notepad to see the raw rtf code. Copy the required tags & stuff to the 'rtf' property of your Rich Text Box (append to existing text).
There is some trial and error involved but works.
With C#, I use place holder StringBuilder objects with the necessary rtf code. Then I just append the image path.
This is a workaround for not having to learn the RTF syntax.
My own version that I posted in a new thread, apparently I should have searched and posted it here. Anyway, using the clipboard again, very easy.
private void button1_Click(object sender, EventArgs e)
{
openFileDialog1.Filter = "Images |*.bmp;*.jpg;*.png;*.gif;*.ico";
openFileDialog1.Multiselect = false;
openFileDialog1.FileName = "";
DialogResult result = openFileDialog1.ShowDialog();
if (result == DialogResult.OK)
{
Image img = Image.FromFile(openFileDialog1.FileName);
Clipboard.SetImage(img);
richTextBox1.Paste();
richTextBox1.Focus();
}
else
{
richTextBox1.Focus();
}
}
}
If you were in C++, the way to do it is thru OLE. More specifically, if you search Google for ImageDataObject it will show C++ code how to insert a HBITMAP into the RTF Control. One link is here.
Now, how this translates into .Net code, I don't know. I currently don't have the time to work thru the details.
I was also looking for something for this same task and found this ->
http://sourceforge.net/projects/netrtfwriter/
You can generate any type of RTF text that you would want and then use it however you wish. Very well structured example which will auto sense the image type being used (jpg/jpeg/png etc) and worked for the image files I have been using. If you are in a hurry then this is a great RTF generator!
All I did was make a small pictureBox control in c# and made sure it was hidden behind another object big enough to hide it. Then I made a button to insert a picture, and it loaded the pictureBox with the image then it puts it in the richTextBox then it clears the pictureBox control.
Here is the code.
private void InsertPicture_Click(object sender, EventArgs e)
{
{
if (openFileDialog4.ShowDialog() == DialogResult.OK)
{
// Show the Open File dialog. If the user clicks OK, load the
// picture that the user chose.
pictureBox2.Load(openFileDialog4.FileName);
Clipboard.SetImage(pictureBox2.Image);
pictureBox2.Image = null;
this.richTextBox1.Paste();
}
}
}
After inserting the code to do it with the clipboard, type in Clipboard.Clear();. It works well and it doesn't clear everything, only the item last added to the clipboard.
Full Code:
private void addPictureToRTB()
{
using (OpenFileDialog ofd = new OpenFileDialog() { Filter = "Pictures|*.png" })
{
if (ofd.ShowDialog() == DialogResult.OK)
{
ClipBoard.SetImage(Image.FromFile(ofd.FileName));
richTextBox.Paste();
Clipboard.Clear();
}
}
}
Then reference this function where you need to.
Several hours surfing for solution to insert image without loosing quality and fixed the gray background with transparent image/png
// assuming the image is in your Resources
var img = Resources.ImageWithTransparentBckgrnd;
var g = Graphics.FromImage(img);
using (var ms = new MemoryStream())
{
img.Save(ms, ImageFormat.Png);
IntPtr ipHdc = g.GetHdc();
Metafile mf = new Metafile(ms, ipHdc);
g = Graphics.FromImage(mf);
g.FillEllipse(Brushes.White, 0, 0, 16, 16); // size you want to fill in
g.Dispose();
mf.Save(ms, ImageFormat.Png);
IDataObject dataObject = new DataObject();
dataObject.SetData("PNG", false, ms);
Clipboard.SetDataObject(dataObject, false);
richTextBox1.Paste();
SendKeys.Send("{RIGHT}");
richTextBox1.Focus();
}

Finding & Replacing text in a MS Word textbox

I am trying to replace the temporary text in a word document with new text from a list. It works if the text is not in a shape, but once it tries to find the text in a textbox it throws an error. Here is what I have so far:
public void FindReplace(List<repvals> replaceVals, string docLocation, int listLen)
{
//Opens a new Word application
var app = new Microsoft.Office.Interop.Word.Application();
//Opens the .docx
var doc = app.Documents.Open(docLocation, true, false);
//Selects the document
var range = doc.Range();
for (int i = 0; i < listLen; i++)
{
//Finds the parameter, then replaces
range.Find.Execute(FindText: Convert.ToString(replaceVals[i].tempVal), Replace: WdReplace.wdReplaceAll, ReplaceWith: Convert.ToString(replaceVals[i].Boxes));
var shapes = doc.Shapes;
//Finds text within textboxes, then changes them
foreach (Microsoft.Office.Interop.Word.Shape shape in shapes)
{
var initialText = shape.TextFrame.TextRange.Text;
var resultingText = initialText.Replace(Convert.ToString(replaceVals[i].tempVal), Convert.ToString(replaceVals[i].Boxes));
shape.TextFrame.TextRange.Text = resultingText;
}
}
//prints document
doc.Save();
doc.Close();
//fully closes Word
Marshal.ReleaseComObject(app);
}
The problem occurs when it hits
var initialText = shape.TextFrame.TextRange.Text;
And throws an error saying: "This object does not support attached text."
The text in the shapes are nothing special. (e.g. tDATE, tNAME, etc.)
Any ideas?
I found the answer. Turns out my code was fine, however the document I was using (which I didn't write), had another shape on the second to last page to form a place to sign your name. I replaced that with an underscore, ran the code, and everything changed perfectly.
For those who also experience this problem, try checking how many shapes your foreach loop has counted:
http://i.imgur.com/1yNrL4p.png
Thank you Andrew and varocarbas for the help
*"In 2003 the AltText default for a standard textbox WAS the contained text BUT since you can change the Alt Text to NOT match it was never a good idea to read it this way. In 2010 the default for Alt Text is blank
If the textbox is named "Text Box 2" (substitute the correct name if not)
MsgBox ActiveDocument.Shapes("Text Box 2").TextFrame.TextRange should work."*
--
John SR Wilson
http://answers.microsoft.com/en-us/office/forum/office_2010-customize/shapesalternativetext-is-blank-for-the-docx/7671c746-2c2b-41d9-b7de-389a766587a7?page=2&msgId=31041d67-e62b-4ce0-b283-57fd6a4ff6b2

Categories

Resources