Problem beim Ersetzen von Platzhaltern in Word-Dokument mit C#-Code

  • .NET (FX) 4.5–4.8
  • C#

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von VaporiZed.

    Problem beim Ersetzen von Platzhaltern in Word-Dokument mit C#-Code

    Hallo Community,

    ich arbeite derzeit an einem Projekt, bei dem ich Platzhalter in einem Word-Dokument (Form4) durch Werte aus einer Windows Forms-Anwendung mit C#-Code ersetzen muss. Leider funktioniert mein Code nicht wie erwartet, und ich benötige dringend Hilfe.

    Das komische daran ist, dass einige Platzhalter tatsächlich ersetzt werden, aber nur die hier nicht:
    [name]
    [straße]
    [stadt]
    [anfang]
    [angebotsnummer]
    [baustellename]
    [angebotsdatum]
    [steuer]
    [footer]
    [iban] und [bic]

    Aber alles andere funktioniert?

    Quellcode:
    Spoiler anzeigen


    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.ComponentModel;
    4. using System.Data;
    5. using System.Drawing;
    6. using System.Linq;
    7. using System.Text;
    8. using System.Threading.Tasks;
    9. using System.Windows.Forms;
    10. using DocumentFormat.OpenXml.Packaging;
    11. namespace CansProgramm
    12. {
    13. public partial class Form4 : Form
    14. {
    15. private string userDocumentsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
    16. private string basePath = "Cans Rechnungs und Angebots Programm";
    17. private string templatesPath = "Template";
    18. private string angebotePath = "Angebote";
    19. private string settingsFilePath = "Einstellungen\\Informationen.txt";
    20. public Form4()
    21. {
    22. InitializeComponent();
    23. for (int i = 1; i <= 10; i++)
    24. {
    25. TextBox fiyatTextBox = this.Controls.Find("fiyat" + i + "TxtBox", true).FirstOrDefault() as TextBox;
    26. if (fiyatTextBox != null)
    27. {
    28. fiyatTextBox.TextChanged += new EventHandler(FiyatTextBoxes_TextChanged);
    29. }
    30. }
    31. }
    32. private void FiyatTextBoxes_TextChanged(object sender, EventArgs e)
    33. {
    34. for (int i = 1; i < 10; i++)
    35. {
    36. TextBox fiyatTextBox = this.Controls.Find("fiyat" + i + "TxtBox", true).FirstOrDefault() as TextBox;
    37. TextBox nextFiyatTextBox = this.Controls.Find("fiyat" + (i + 1) + "TxtBox", true).FirstOrDefault() as TextBox;
    38. TextBox nextAciklamaTextBox = this.Controls.Find("aciklama" + (i + 1) + "TxtBox", true).FirstOrDefault() as TextBox;
    39. TextBox nextStückTextBox = this.Controls.Find("stück" + (i + 1) + "TxtBox", true).FirstOrDefault() as TextBox;
    40. TextBox nextPosTextBox = this.Controls.Find("pos" + (i + 1) + "TxtBox", true).FirstOrDefault() as TextBox;
    41. if (fiyatTextBox != null && !string.IsNullOrWhiteSpace(fiyatTextBox.Text))
    42. {
    43. if (nextFiyatTextBox != null) nextFiyatTextBox.Enabled = true;
    44. if (nextAciklamaTextBox != null) nextAciklamaTextBox.Enabled = true;
    45. if (nextStückTextBox != null) nextStückTextBox.Enabled = true;
    46. if (nextPosTextBox != null) nextPosTextBox.Enabled = true;
    47. }
    48. else
    49. {
    50. if (nextFiyatTextBox != null) nextFiyatTextBox.Enabled = false;
    51. if (nextAciklamaTextBox != null) nextAciklamaTextBox.Enabled = false;
    52. if (nextStückTextBox != null) nextStückTextBox.Enabled = false;
    53. if (nextPosTextBox != null) nextPosTextBox.Enabled = false;
    54. }
    55. }
    56. }
    57. private void label6_Click(object sender, EventArgs e)
    58. {
    59. }
    60. private void fullsaveBtn_Click(object sender, EventArgs e)
    61. {
    62. string angebotPath = Path.Combine(userDocumentsPath, basePath, angebotePath, angebotsnummerTxtBox.Text + ".docx");
    63. string angebotTemplatePath = Path.Combine(userDocumentsPath, basePath, templatesPath, "Angebot.docx");
    64. CreateDocumentFromTemplate(angebotTemplatePath, angebotPath);
    65. }
    66. private void Form4_Load(object sender, EventArgs e)
    67. {
    68. string angebotTemplatePath = Path.Combine(userDocumentsPath, basePath, templatesPath, "Angebot.docx");
    69. string rechnungTemplatePath = Path.Combine(userDocumentsPath, basePath, templatesPath, "Rechnung.docx");
    70. if (!File.Exists(angebotTemplatePath) || !File.Exists(rechnungTemplatePath))
    71. {
    72. MessageBox.Show("Die erforderlichen Vorlagendateien 'Angebot.docx' und 'Rechnung.docx' wurden nicht im Template-Ordner gefunden.", "Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
    73. this.Close();
    74. }
    75. }
    76. private void CreateDocumentFromTemplate(string templatePath, string newFilePath)
    77. {
    78. try
    79. {
    80. File.Copy(templatePath, newFilePath, true);
    81. using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(newFilePath, true))
    82. {
    83. ReplaceWordPlaceholders(wordDoc);
    84. ReplaceInformationFromSettings(wordDoc);
    85. wordDoc.Save();
    86. }
    87. MessageBox.Show("Das Dokument wurde erfolgreich erstellt und unter '" + newFilePath + "' gespeichert.", "Erfolg", MessageBoxButtons.OK, MessageBoxIcon.Information);
    88. }
    89. catch (Exception ex)
    90. {
    91. MessageBox.Show("Fehler beim Erstellen des Dokuments: " + ex.Message, "Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
    92. }
    93. }
    94. private void ReplaceWordPlaceholders(WordprocessingDocument wordDoc)
    95. {
    96. ReplaceWordPlaceholder(wordDoc, "[firmenname]", firmennameTxtBox.Text);
    97. ReplaceWordPlaceholder(wordDoc, "[name]", nameTxtBox.Text);
    98. ReplaceWordPlaceholder(wordDoc, "[straße]", straßeTxtBox.Text);
    99. ReplaceWordPlaceholder(wordDoc, "[stadt]", stadtTxtBox.Text);
    100. ReplaceWordPlaceholder(wordDoc, "[baustellenname]", bauTxtBox.Text);
    101. ReplaceWordPlaceholder(wordDoc, "[angebotsnummer]", angebotsnummerTxtBox.Text);
    102. ReplaceWordPlaceholder(wordDoc, "[angebotsdatum]", DateTime.Now.ToString("dd.MM.yyyy"));
    103. for (int i = 1; i <= 10; i++)
    104. {
    105. TextBox posTextBox = this.Controls.Find("pos" + i + "TxtBox", true).FirstOrDefault() as TextBox;
    106. TextBox aciklamaTextBox = this.Controls.Find("aciklama" + i + "TxtBox", true).FirstOrDefault() as TextBox;
    107. TextBox stückTextBox = this.Controls.Find("stück" + i + "TxtBox", true).FirstOrDefault() as TextBox;
    108. TextBox fiyatTextBox = this.Controls.Find("fiyat" + i + "TxtBox", true).FirstOrDefault() as TextBox;
    109. ReplaceWordPlaceholder(wordDoc, "[pos" + i + "]", posTextBox?.Text ?? "");
    110. ReplaceWordPlaceholder(wordDoc, "[beschreibung" + i + "]", aciklamaTextBox?.Text ?? "");
    111. ReplaceWordPlaceholder(wordDoc, "[stück" + i + "]", stückTextBox?.Text ?? "");
    112. ReplaceWordPlaceholder(wordDoc, "[preis" + i + "]", fiyatTextBox?.Text ?? "");
    113. }
    114. }
    115. private void ReplaceInformationFromSettings(WordprocessingDocument wordDoc)
    116. {
    117. string settingsPath = Path.Combine(userDocumentsPath, basePath, settingsFilePath);
    118. if (File.Exists(settingsPath))
    119. {
    120. string[] lines = File.ReadAllLines(settingsPath);
    121. if (lines.Length > 0) ReplaceWordPlaceholder(wordDoc, "[inhaberunternehmen]", lines[0]);
    122. if (lines.Length > 1) ReplaceWordPlaceholder(wordDoc, "[inhabername]", lines[1]);
    123. if (lines.Length > 2) ReplaceWordPlaceholder(wordDoc, "[inhaberstraße]", lines[2]);
    124. if (lines.Length > 3) ReplaceWordPlaceholder(wordDoc, "[steuer]", lines[3]);
    125. if (lines.Length > 4) ReplaceWordPlaceholder(wordDoc, "[inhabertelefon]", lines[4]);
    126. if (lines.Length > 5) ReplaceWordPlaceholder(wordDoc, "[inhaberemail]", lines[5]);
    127. if (lines.Length > 6) ReplaceWordPlaceholder(wordDoc, "[iban]", lines[6]);
    128. if (lines.Length > 7) ReplaceWordPlaceholder(wordDoc, "[bic]", lines[7]);
    129. if (lines.Length > 8) ReplaceWordPlaceholder(wordDoc, "[inhaberstadt]", lines[8]);
    130. if (lines.Length > 9) ReplaceWordPlaceholder(wordDoc, "[footer]", lines[9]);
    131. string angebotInfoPath = Path.Combine(userDocumentsPath, basePath, "Einstellungen", "Angebot.txt");
    132. if (File.Exists(angebotInfoPath))
    133. {
    134. string angebotInfo = File.ReadAllText(angebotInfoPath);
    135. ReplaceWordPlaceholder(wordDoc, "[anfang]", angebotInfo);
    136. }
    137. }
    138. else
    139. {
    140. MessageBox.Show("Die Einstellungsdatei 'Informationen.txt' wurde nicht gefunden.", "Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
    141. }
    142. }
    143. private void ReplaceWordPlaceholder(WordprocessingDocument wordDoc, string placeholder, string replacement)
    144. {
    145. ReplaceWordPlaceholderInPart(wordDoc.MainDocumentPart, placeholder, replacement);
    146. foreach (var headerPart in wordDoc.MainDocumentPart.HeaderParts)
    147. {
    148. ReplaceWordPlaceholderInPart(headerPart, placeholder, replacement);
    149. }
    150. foreach (var footerPart in wordDoc.MainDocumentPart.FooterParts)
    151. {
    152. ReplaceWordPlaceholderInPart(footerPart, placeholder, replacement);
    153. }
    154. foreach (var text in wordDoc.MainDocumentPart.Document.Descendants<DocumentFormat.OpenXml.Wordprocessing.Text>())
    155. {
    156. if (text.Text.Contains(placeholder))
    157. {
    158. text.Text = text.Text.Replace(placeholder, replacement);
    159. }
    160. }
    161. }
    162. private void ReplaceWordPlaceholderInPart(OpenXmlPart part, string placeholder, string replacement)
    163. {
    164. var textsToReplace = new List<DocumentFormat.OpenXml.Wordprocessing.Text>();
    165. foreach (var text in part.RootElement.Descendants<DocumentFormat.OpenXml.Wordprocessing.Text>())
    166. {
    167. if (text.Text.Contains(placeholder))
    168. {
    169. textsToReplace.Add(text);
    170. }
    171. }
    172. foreach (var text in textsToReplace)
    173. {
    174. text.Text = text.Text.Replace(placeholder, replacement);
    175. }
    176. }
    177. }
    178. }


    Zur Sicherheitshalber hier der code von Form6
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.ComponentModel;
    4. using System.Data;
    5. using System.Drawing;
    6. using System.Linq;
    7. using System.Text;
    8. using System.Threading.Tasks;
    9. using System.Windows.Forms;
    10. using System.IO;
    11. namespace CansProgramm
    12. {
    13. public partial class Form6 : Form
    14. {
    15. private string userDocumentsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
    16. private string basePath = "Cans Rechnungs und Angebots Programm";
    17. private string settingsFilePath = "Einstellungen\\Informationen.txt";
    18. public Form6()
    19. {
    20. InitializeComponent();
    21. }
    22. private void LoadSettings(string filePath)
    23. {
    24. string angebotFilePath = Path.Combine(userDocumentsPath, basePath, "Einstellungen", "angebot.txt");
    25. string rechnungFilePath = Path.Combine(userDocumentsPath, basePath, "Einstellungen", "rechnung.txt");
    26. if (File.Exists(filePath))
    27. {
    28. string[] lines = File.ReadAllLines(filePath);
    29. // Laden der Einstellungen in die Textboxen, wenn vorhanden
    30. if (lines.Length >= 9)
    31. {
    32. firmennameTxtBox.Text = lines[0];
    33. nameTxtBox.Text = lines[1];
    34. straßeTxtBox.Text = lines[2];
    35. steuernummerTxtBox.Text = lines[3];
    36. telefonnummerTxtBox.Text = lines[4];
    37. emailTxtBox.Text = lines[5];
    38. ibanTxtBox.Text = lines[6];
    39. bicTxtBox.Text = lines[7];
    40. stadtTxtBox.Text = lines[8];
    41. footerTxtBox.Text = lines[9];
    42. }
    43. else
    44. {
    45. MessageBox.Show("Einige oder alle Einstellungen fehlen in 'Informationen.txt'.");
    46. }
    47. }
    48. else
    49. {
    50. MessageBox.Show("Keine Einstellungen in 'Informationen.txt' gespeichert.");
    51. }
    52. // Laden der Inhalte der RichTextBoxen
    53. LoadRichTextBoxContent(angebotFilePath, angebotmailRichTxtBox);
    54. LoadRichTextBoxContent(rechnungFilePath, rechnungRichTxtBox);
    55. }
    56. private void Form6_Load(object sender, EventArgs e)
    57. {
    58. string fullPath = Path.Combine(userDocumentsPath, basePath);
    59. // Erstellen der benötigten Ordner
    60. CreateDirectoryIfNotExists(fullPath, "Einstellungen");
    61. CreateDirectoryIfNotExists(fullPath, "Angebote");
    62. CreateDirectoryIfNotExists(fullPath, "Rechnungen");
    63. CreateDirectoryIfNotExists(fullPath, "Template"); // Überprüfung und Erstellung des "Template"-Ordners
    64. // Überprüfen und Laden der Einstellungen
    65. LoadSettings(Path.Combine(fullPath, settingsFilePath));
    66. }
    67. private void CreateDirectoryIfNotExists(string basePath, string folderName)
    68. {
    69. string path = Path.Combine(basePath, folderName);
    70. if (!Directory.Exists(path))
    71. {
    72. Directory.CreateDirectory(path);
    73. }
    74. }
    75. private void LoadRichTextBoxContent(string filePath, RichTextBox richTextBox)
    76. {
    77. if (File.Exists(filePath))
    78. {
    79. richTextBox.Text = File.ReadAllText(filePath);
    80. }
    81. }
    82. private void speichernBtn_Click(object sender, EventArgs e)
    83. {
    84. try
    85. {
    86. string[] lines = {
    87. firmennameTxtBox.Text,
    88. nameTxtBox.Text,
    89. straßeTxtBox.Text,
    90. steuernummerTxtBox.Text,
    91. telefonnummerTxtBox.Text,
    92. emailTxtBox.Text,
    93. ibanTxtBox.Text,
    94. bicTxtBox.Text,
    95. stadtTxtBox.Text,
    96. footerTxtBox.Text
    97. // Die RichTextBox-Inhalte werden nicht mehr hier gespeichert
    98. };
    99. // Speichern der grundlegenden Einstellungen
    100. File.WriteAllLines(Path.Combine(userDocumentsPath, basePath, settingsFilePath), lines);
    101. // Speichern der Inhalte der RichTextBoxen in separaten Dateien
    102. File.WriteAllText(Path.Combine(userDocumentsPath, basePath, "Einstellungen", "angebot.txt"), angebotmailRichTxtBox.Text);
    103. File.WriteAllText(Path.Combine(userDocumentsPath, basePath, "Einstellungen", "rechnung.txt"), rechnungRichTxtBox.Text);
    104. MessageBox.Show("Einstellungen erfolgreich gespeichert.", "Erfolg", MessageBoxButtons.OK, MessageBoxIcon.Information);
    105. }
    106. catch (Exception ex)
    107. {
    108. MessageBox.Show("Fehler beim Speichern der Einstellungen: " + ex.Message, "Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
    109. }
    110. }
    111. }
    112. }



    Ich habe alles versucht, aber diese Platzhalter werden nicht ersetzt, während andere erfolgreich ersetzt werden.

    Das Problem ist, dass die Platzhalter im Dokument nicht korrekt bzw. ÜBERHAUPT ersetzt werden!!, obwohl ich sicher bin, dass die Platzhalter im Dokument vorhanden sind. Ich habe auch das Dokument im Anhang hinzugefügt....

    Könnte jemand mir bitte bei der Identifizierung des Problems und der Behebung helfen? Ich wäre für jede Unterstützung sehr dankbar.

    Vielen Dank im Voraus!


    Ach übrigends ich habe auch Platzhalter gesetzt, habe nichts verstanden alles war clean, dann doch alte Methode MsgBox benutzt, tatsächlich nach pos1 etc. springt er zu email platzhalter und o.g. Platzhalter ignoriert er.

    Thema verschoben; Das Thema wird automatisch dort erstellt, wo man sich befindet, wenn man auf [✱ Neues Thema] klickt. ~VaporiZed
    Dateien
    • Angebot.docx

      (34,79 kB, 116 mal heruntergeladen, zuletzt: )

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VaporiZed“ ()

    mehmetqan schrieb:

    string[] lines = File.ReadAllLines(settingsPath);


    So liest du die DOCX Datei ein? Dann schau mal im Anhang, dann sollte klar sein warum das nicht klappt. DOCX ist nun mal kein Plaintext.

    Huch, hab den Code nicht richtig gelesen.

    PS

    mehmetqan schrieb:

    Form4 : Form

    Du hast den Thread mit WPF getagt. Du arbeitest allerdings mit Forms, nicht mit WPF. Und gib auch deinen Forms anständige Namen.

    Bilder
    • Unbenannt.png

      25,68 kB, 792×281, 118 mal angesehen
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „DTF“ ()

    @mehmetqan Ich habe einen ähnlichen Sachverhalt.
    Ich arbeite mit RichText, das RTF-Dokument editiere ich mit write.exe, nicht aber mit Word.
    Das funktioniert problemlos.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    In Deiner Methode ReplaceWordPlaceholderInPart kommt das für part.RootElement.Descendants<DocumentFormat.OpenXml.Wordprocessing.Text>() raus:

    Keine weiteren Fragen, Eurer Ehren.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Den Innereien des Worddokuments zufolge* sind die Bereiche bei z.B. [Firmenname] aufgeteilt. 1. Teil [, 2. Teil Firmenname, 3. Teil ]. Löschst Du in dem Worddokument den Text raus und schreibst in genau dieser Reihenfolge [Firmenname] (also nicht erst die Klammern und dazwischen den Text oder zuerst den Text und dann die Klammern!), wird das als ein Teil abgespeichert und dann auch so ersetzt, wie Du das willst, siehe Anhang. Der Nachteil ist, dass Du die genannte Textseparierung nicht innerhalb Word erkennen kannst.

    * dazu die Dateiendung auf zip ändern, Archiv öffnen und die Datei word\document.xml ansehen
    Bilder
    • NachVereinheitlichung.png

      5,08 kB, 301×272, 81 mal angesehen
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Eh … ja bitte. Sonst ergäbe der Thread wenig Sinn, wenn ein Problem besprochen wird, der Fehler gefunden wurde, eine Lösung existiert, aber diese hier nicht auftaucht. Das würde anderen Leuten, die vor dem gleichen oder ähnlichen Problemen stehen, nix bringen. Daher bitte Deinen Lösungsweg posten.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Hi,

    auf Anweisung des Admins habe ich mich darauf konzentriert, anstelle eines DOCX-Dokuments ein altmodisches XLSX-Dokument zu bearbeiten.

    Die Lösung war wie folgt:

    Ich habe ein XLSX-Dokument im A4-Format gestaltet (es gibt viele Layouts oder Tutorials auf YouTube).

    Nachdem dies erledigt war, reichte mir tatsächlich ein Rich Text aus. Ich benötigte nämlich 3 Spalten, und diese werden automatisch in verschiedene Spalten einer Rich-Text-Box verteilt, wenn man mit (*) - dem Sternzeichen - dem Programm zeigt, dass man dies in eine neue Spalte einfügen möchte.

    für PDF einfach die Methode SaveAs benutzen, ihr benötigt keine andere Nuget o.ä. ist im Code genau gezeigt.

    C#-Quellcode

    1. SaveFileDialog saveFileDialog = new SaveFileDialog();
    2. saveFileDialog.Filter = "PDF-Datei (*.pdf)|*.pdf";
    3. saveFileDialog.DefaultExt = "pdf";
    4. saveFileDialog.FileName = $"{nameTxtBox.Text} - {DateTime.Now.ToString("dd-MM-yyyy")}.pdf";
    5. if (saveFileDialog.ShowDialog() == DialogResult.OK)
    6. {
    7. // Exportieren des Arbeitsblatts als PDF
    8. sheet.ExportAsFixedFormat(XlFixedFormatType.xlTypePDF, saveFileDialog.FileName, XlFixedFormatQuality.xlQualityStandard, true, true, 1, 56, false);
    9. MessageBox.Show("PDF erfolgreich gespeichert.");
    10. lastSavedPdfPath = saveFileDialog.FileName;
    11. }


    Beispiel:

    Testbeschreibung * 3 * 35,35


    Spalte A
    Spalte B
    Spalte C
    Beschreibung
    Stück/Stunde
    Preis
    Testbeschreibung
    335,35


    Mit freundlichen Grüßen,
    mehmetqan

    GUCKT EUCH UNBEDING DIE SCREENSHOOTS AN WEGEN UI

    @VaporiZed ich habe nicht geschafft, die Bilder sofort hier sichtbar zu machen, kannst du das vielleicht nochmal editieren bitte?

    Screenshoots (Autolöschung ist aktiv 6 Monate ab 12.02.2024): Form1: ibb.co/HThp3zZ
    Form2: https://ibb.co/zf8Jz9C

    ebenso habe ich ein Auto Mail hinzugefügt, sodass der zuletzt gespeicherte durch ein Link-Label mit einem klick den .pdf verzeichniss sich merkt, und das ganze als Anhang versendet, je nachdem was bei der Combobox ausgewählt wurden ist, macht er auch eine Nachricht automatisch selber.

    Form1.Quellcode:
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.ComponentModel;
    4. using System.Data;
    5. using System.Drawing;
    6. using System.Linq;
    7. using System.Text;
    8. using System.Threading.Tasks;
    9. using System.Windows.Forms;
    10. using System.IO;
    11. using Microsoft.Office.Interop.Excel;
    12. namespace CansProjektAngebot
    13. {
    14. public partial class Form1 : Form
    15. {
    16. private string lastSavedPdfPath = "";
    17. public Form1()
    18. {
    19. InitializeComponent();
    20. }
    21. private void pdfBtn_Click(object sender, EventArgs e)
    22. {
    23. if (string.IsNullOrEmpty(rechnungsnummerTxtBox.Text))
    24. {
    25. MessageBox.Show("Es fehlt Rechnungsnummer");
    26. rechnungsnummerTxtBox.Focus();
    27. return;
    28. }
    29. if (string.IsNullOrEmpty(baustelleTxtBox.Text))
    30. {
    31. MessageBox.Show("Es fehlt Baustellenort");
    32. baustelleTxtBox.Focus();
    33. return;
    34. }
    35. string[] lines = richTextBox1.Text.Split('\n');
    36. if (lines.Length > 9)
    37. {
    38. MessageBox.Show("Es dürfen nicht mehr als 9 Beschreibungen eingegeben werden.");
    39. richTextBox1.Focus();
    40. return;
    41. }
    42. string documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
    43. string originalExcelFilePath = Path.Combine(documentsPath, "Template_CansProgramm.xlsx");
    44. string tempExcelFilePath = Path.Combine(documentsPath, $"Temp_{Guid.NewGuid()}.xlsx");
    45. // Erstellen einer Kopie der Template-Datei
    46. File.Copy(originalExcelFilePath, tempExcelFilePath, true);
    47. var excelApp = new Microsoft.Office.Interop.Excel.Application();
    48. var workbook = excelApp.Workbooks.Open(tempExcelFilePath);
    49. var sheet = (Worksheet)workbook.Sheets[comboBox1.SelectedItem.ToString()];
    50. sheet.Cells[7, 2].Value2 = firmennameTxtBox.Text;
    51. sheet.Cells[8, 2].Value2 = nameTxtBox.Text;
    52. sheet.Cells[9, 2].Value2 = straßeTxtBox.Text;
    53. sheet.Cells[10, 2].Value2 = plzTxtBox.Text;
    54. sheet.Cells[19, 2].Value2 = rechnungsnummerTxtBox.Text;
    55. sheet.Cells[19, 3].Value2 = baustelleTxtBox.Text;
    56. int row = 23;
    57. foreach (string line in lines)
    58. {
    59. string[] items = line.Split('*');
    60. if (items.Length >= 3)
    61. {
    62. sheet.Cells[row, 2].Value2 = items[0].Trim();
    63. sheet.Cells[row, 5].Value2 = items[1].Trim();
    64. sheet.Cells[row, 6].Value2 = items[2].Trim();
    65. row++;
    66. }
    67. }
    68. // Speichern der Änderungen
    69. workbook.Save();
    70. SaveFileDialog saveFileDialog = new SaveFileDialog();
    71. saveFileDialog.Filter = "PDF-Datei (*.pdf)|*.pdf";
    72. saveFileDialog.DefaultExt = "pdf";
    73. saveFileDialog.FileName = $"{nameTxtBox.Text} - {DateTime.Now.ToString("dd-MM-yyyy")}.pdf";
    74. if (saveFileDialog.ShowDialog() == DialogResult.OK)
    75. {
    76. // Exportieren des Arbeitsblatts als PDF
    77. sheet.ExportAsFixedFormat(XlFixedFormatType.xlTypePDF, saveFileDialog.FileName, XlFixedFormatQuality.xlQualityStandard, true, true, 1, 56, false);
    78. MessageBox.Show("PDF erfolgreich gespeichert.");
    79. lastSavedPdfPath = saveFileDialog.FileName;
    80. }
    81. // Schließen der Arbeitsmappe und Excel
    82. workbook.Close(false);
    83. excelApp.Quit();
    84. // Löschen der temporären Kopie
    85. File.Delete(tempExcelFilePath);
    86. }
    87. private void Form1_Load(object sender, EventArgs e)
    88. {
    89. }
    90. private void pdfandmailBtn_Click(object sender, EventArgs e)
    91. {
    92. Form2 mailForm = new Form2(lastSavedPdfPath, comboBox1.Text);
    93. mailForm.Show();
    94. }
    95. }
    96. }


    Form2 (Mail senden) Quellcode:
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.ComponentModel;
    4. using System.Data;
    5. using System.Drawing;
    6. using System.IO;
    7. using System.Linq;
    8. using System.Net.Mail;
    9. using System.Net;
    10. using System.Text;
    11. using System.Threading.Tasks;
    12. using System.Windows.Forms;
    13. namespace CansProjektAngebot
    14. {
    15. public partial class Form2 : Form
    16. {
    17. private string pdfPath;
    18. private string comboBoxText;
    19. public Form2(string pdfPath, string comboBoxText)
    20. {
    21. this.pdfPath = pdfPath;
    22. this.comboBoxText = comboBoxText;
    23. InitializeComponent();
    24. }
    25. private void Form2_Load(object sender, EventArgs e)
    26. {
    27. betreffTxtBox.Text = $"{comboBoxText} | {Path.GetFileName(pdfPath)} | {DateTime.Now.ToString("dd-MM-yyyy")} | [Firmenname]";
    28. if (comboBoxText == "Rechnung")
    29. {
    30. beschreibungRichTxtBox.Text = "<!DOCTYPE html><html><head><title>Angebots-E-Mail</title><style>.email-container { font-family: Arial, sans-serif; color: #333333; padding: 20px; border: 1px solid #DDDDDD; max-width: 600px; margin: auto; }.header { background-color: black; color: white; padding: 10px; text-align: center; }.content { padding: 20px; text-align: left; }.signature { padding-top: 20px; border-top: 1px solid #DDDDDD; font-size: 0.9em; }.footer { background-color: #DDDDDD; padding: 10px; text-align: center; }</style></head><body><div class=\"email-container\"><div class=\"header\"><h1>[Firmenname] - Rechnung</h1></div><div class=\"content\"><p>Sehr geehrte Damen und Herren,<br><br>anbei finden Sie die Rechnung für die von uns erbrachten Dienstleistungen. <br>Wir bitten Sie, den ausstehenden Betrag innerhalb der nächsten 14 Tage auf das in dem Dokument angegebene Bankkonto zu überweisen.<br><br>Wir danken Ihnen für Ihr Vertrauen und die angenehme Zusammenarbeit. Es würde uns sehr freuen, auch in Zukunft mit Ihnen zusammenarbeiten zu dürfen.<br><br>Mit freundlichen Grüßen,<br><br>[Name]<br>[Firmenname]</p></div></div></body></html>\r\n";
    31. }
    32. else if (comboBoxText == "Angebot")
    33. {
    34. beschreibungRichTxtBox.Text = "<!DOCTYPE html><html><head><title>Angebots-E-Mail</title><style>.email-container { font-family: Arial, sans-serif; color: #333333; padding: 20px; border: 1px solid #DDDDDD; max-width: 600px; margin: auto; }.header { background-color: black; color: white; padding: 10px; text-align: center; }.content { padding: 20px; text-align: left; }.signature { padding-top: 20px; border-top: 1px solid #DDDDDD; font-size: 0.9em; }.footer { background-color: #DDDDDD; padding: 10px; text-align: center; }</style></head><body><div class=\"email-container\"><div class=\"header\"><h1>[Firmenname] - Angebot</h1></div><div class=\"content\"><p>Sehr geehrte Damen und Herren,<br><br>im Anhang finden Sie unser Angebot für die von Ihnen angefragten Dienstleistungen. <br><br>Dieses Angebot ist ab dem heutigen Sendedatum 30 Tage gültig.<br><br>Für Fragen oder falls Unklarheiten bestehen, stehen wir Ihnen gerne per E-Mail oder telefonisch zur Verfügung.<br><br>Vielen Dank und freundliche Grüße,<br><br>[Name]<br>[Firmenname]</p></div></div></body></html>\r\n";
    35. }
    36. }
    37. private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
    38. {
    39. anhangLabel.Text = pdfPath;
    40. }
    41. private void mailsendenBtn_Click(object sender, EventArgs e)
    42. {
    43. SendEmail();
    44. }
    45. private void SendEmail()
    46. {
    47. try
    48. {
    49. var smtpClient = new SmtpClient("smtp.outlook.com")
    50. {
    51. Port = 587,
    52. Credentials = new NetworkCredential("[E-Mail-Adresse]", "[Passwort]"), // Verwenden Sie hier sicherheitsbewusst Ihre Anmeldeinformationen
    53. EnableSsl = true,
    54. };
    55. var mailMessage = new MailMessage
    56. {
    57. From = new MailAddress("[E-Mail-Adresse]"),
    58. Subject = betreffTxtBox.Text,
    59. Body = beschreibungRichTxtBox.Text,
    60. IsBodyHtml = true,
    61. };
    62. mailMessage.To.Add(empfängerTxtBox.Text);
    63. string attachmentInfo = "";
    64. if (!string.IsNullOrEmpty(anhangLabel.Text))
    65. {
    66. mailMessage.Attachments.Add(new Attachment(anhangLabel.Text));
    67. attachmentInfo = $"\nAnhang: {Path.GetFileName(anhangLabel.Text)}";
    68. }
    69. smtpClient.Send(mailMessage);
    70. // Erfolgsmeldung
    71. MessageBox.Show($"E-Mail erfolgreich gesendet.\n\nBetreff: {mailMessage.Subject}\nNachricht: {mailMessage.Body}{attachmentInfo}", "E-Mail gesendet", MessageBoxButtons.OK, MessageBoxIcon.Information);
    72. }
    73. catch (Exception ex)
    74. {
    75. // Fehlermeldung
    76. MessageBox.Show($"Fehler beim Senden der E-Mail: {ex.Message}", "Fehler programmed for [url='https://www.webseitekostenlos.de']www.webseitekostenlos.de[/url]", MessageBoxButtons.OK, MessageBoxIcon.Error);
    77. }
    78. }
    79. private void showBtn_Click(object sender, EventArgs e)
    80. {
    81. string htmlContent = beschreibungRichTxtBox.Text;
    82. }
    83. }
    84. }



    @VaporiZed passt das so?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „mehmetqan“ ()

    Bilder bitte forenintern über [+ Erweiterte Antwort] -> _|Dateianhänge|_ -> [Hochladen] posten.

    Die Umfrage ist unnötig. Wenn jemand es hilfreich findet, soll eh der [Hilfreich!]-Button verwendet werden.

    mehmetqan schrieb:

    auf Anweisung des Admins habe ich mich darauf konzentriert, anstelle eines DOCX-Dokuments ein altmodisches XLSX-Dokument zu bearbeiten
    Naja, weder war es eine Anweisung (sondern eine Bitte), noch war die Aufforderung da, es als XLSX zu machen (sondern einfach nur, Deine Lösung zu posten). Und Moderatorenmitteilungen (Admin bin ich nicht) zeigen wir durch roten Text, siehe ganz oben in diesem Post. Aber ok, eine Lösung ist da, das passt dann, wenn Du die Bilder einbettest, wie oben beschrieben.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.