SharpDocx icon indicating copy to clipboard operation
SharpDocx copied to clipboard

Discussion: Is Adding Formatting Options Useful?

Open paulsterling opened this issue 2 years ago • 1 comments

We have been using this project for several years with great success and very few issues (kudos @egonl !) and have recently made some updates to our implementation to expose methods for formatting text in our documents programatically (as opposed to using embedded <%if()..%> statements in the document templates themselves). This gives us finer control over conditional formatting and cleaner docx templates.

We have currently implemented these as specific commands (<% ApplyBoldStyle("My Bold Text"); %>) but could easily make the method more generic and perhaps expose the available formats via an enum or other list of options (<% ApplyStyle(SharpDocxStyles.Bold, "My Bold Text"); %>).

At this point I'm really just gathering input as to if this would be a useful addition to SharpDocx or if it falls outside of what the project is trying to do. If @egonl thinks this is useful, I'll open a PR and add our suggested implementation for review and consideration. Looking forward to input from other users as well.

Here's an example of how we apply a bold style to a parargraph (could also be just at the run level) in our custom class that inherits SharpDocx.DocumentBase :

        protected void ApplyBoldStyle(string content)
        {
            try
            {
                // Usage in template docx: <% ApplyBoldStyle("My Bold Text"); %>

                // Add a paragraph with a run with some text.
                Paragraph p =
                    new Paragraph(
                        new Run(
                            new Text(content) { Space = SpaceProcessingModeValues.Preserve }));

                CurrentCodeBlock.Placeholder.GetParent<Paragraph>().Append(p);

                // If the paragraph has no ParagraphProperties object, create one.
                if (p.Elements<ParagraphProperties>().Count() == 0)
                    p.PrependChild<ParagraphProperties>(new ParagraphProperties());

                // Get the paragraph properties element of the paragraph.
                ParagraphProperties pPr = p.Elements<ParagraphProperties>().First();

                // Get the Styles part for this document.
                StyleDefinitionsPart part = Package.MainDocumentPart.StyleDefinitionsPart;

                // If the Styles part does not exist, add it.
                if (part == null)
                    part = AddStylesPartToPackage(Package);

                bool hasStyle = part.Styles.Descendants<Style>().Any(x => x.StyleId == "sdBold");

                if (!hasStyle)
                {
                    CreateAndAddCharacterStyle(part,
                                            "sdBold",
                                            "Bold Text",
                                            "sdBold");
                }

                // Get a reference to the run (indexed starting with 0).
                Run r = p.Descendants<Run>().ElementAtOrDefault(0);

                // If the Run has no RunProperties object, create one.
                if (r.Elements<RunProperties>().Count() == 0)
                    r.PrependChild<RunProperties>(new RunProperties());

                // Get a reference to the RunProperties.
                RunProperties rPr = r.RunProperties;

                // Set the character style of the run.
                if (rPr.RunStyle == null)
                    rPr.RunStyle = new RunStyle();

                rPr.RunStyle.Val = "sdBold";

            }
            catch(Exception ex)
            {
                // do some logging!
                throw;
            }
        }

paulsterling avatar Dec 15 '22 00:12 paulsterling

Yes please open a PR: I would like to play a little bit with it. Sounds like a good addition. The <% if() %> construction is indeed quite limited.

egonl avatar Dec 16 '22 22:12 egonl