Beispiel #1
0
        private static void SetFormFieldValue(TextInput textInput, string value)
        {                      // Code for http://stackoverflow.com/a/40081925/3103123
            if (value == null) // Reset formfield using default if set.
            {
                if (textInput.DefaultTextBoxFormFieldString != null && textInput.DefaultTextBoxFormFieldString.Val.HasValue)
                {
                    value = textInput.DefaultTextBoxFormFieldString.Val.Value;
                }
            }

            // Enforce max length.
            short maxLength = 0; // Unlimited

            if (textInput.MaxLength != null && textInput.MaxLength.Val.HasValue)
            {
                maxLength = textInput.MaxLength.Val.Value;
            }
            if (value != null && maxLength > 0 && value.Length > maxLength)
            {
                value = value.Substring(0, maxLength);
            }

            // Not enforcing TextBoxFormFieldType (read documentation...).
            // Just note that the Word instance may modify the value of a formfield when user leave it based on TextBoxFormFieldType and Format.
            // A curious example:
            // Type Number, format "# ##0,00".
            // Set value to "2016 was the warmest year ever, at least since 1999.".
            // Open the document and select the field then tab out of it.
            // Value now is "2 016 tht,tt" (the logic behind this escapes me).

            // Format value. (Only able to handle formfields with textboxformfieldtype regular.)
            if (textInput.TextBoxFormFieldType != null &&
                textInput.TextBoxFormFieldType.Val.HasValue &&
                textInput.TextBoxFormFieldType.Val.Value != TextBoxFormFieldValues.Regular)
            {
                throw new ApplicationException("SetFormField: Unsupported textboxformfieldtype, only regular is handled.\r\n" + textInput.Parent.OuterXml);
            }
            if (!string.IsNullOrWhiteSpace(value) &&
                textInput.Format != null &&
                textInput.Format.Val.HasValue)
            {
                switch (textInput.Format.Val.Value)
                {
                case "Uppercase":
                    value = value.ToUpperInvariant();
                    break;

                case "Lowercase":
                    value = value.ToLowerInvariant();
                    break;

                case "First capital":
                    value = value[0].ToString().ToUpperInvariant() + value.Substring(1);
                    break;

                case "Title case":
                    value = System.Globalization.CultureInfo.InvariantCulture.TextInfo.ToTitleCase(value);
                    break;

                default:     // ignoring any other values (not supposed to be any)
                    break;
                }
            }

            // Find run containing "separate" fieldchar.
            Run rTextInput = textInput.Ancestors <Run>().FirstOrDefault();

            if (rTextInput == null)
            {
                throw new ApplicationException("SetFormField: Did not find run containing textinput.\r\n" + textInput.Parent.OuterXml);
            }
            Run rSeparate = rTextInput.ElementsAfter().FirstOrDefault(ru =>
                                                                      ru.GetType() == typeof(Run) &&
                                                                      ru.Elements <FieldChar>().FirstOrDefault(fc =>
                                                                                                               fc.FieldCharType == FieldCharValues.Separate)
                                                                      != null) as Run;

            if (rSeparate == null)
            {
                throw new ApplicationException("SetFormField: Did not find run containing separate.\r\n" + textInput.Parent.OuterXml);
            }

            // Find run containg "end" fieldchar.
            Run rEnd = rTextInput.ElementsAfter().FirstOrDefault(ru =>
                                                                 ru.GetType() == typeof(Run) &&
                                                                 ru.Elements <FieldChar>().FirstOrDefault(fc =>
                                                                                                          fc.FieldCharType == FieldCharValues.End)
                                                                 != null) as Run;

            if (rEnd == null) // Formfield value contains paragraph(s)
            {
                Paragraph p    = rSeparate.Parent as Paragraph;
                Paragraph pEnd = p.ElementsAfter().FirstOrDefault(pa =>
                                                                  pa.GetType() == typeof(Paragraph) &&
                                                                  pa.Elements <Run>().FirstOrDefault(ru =>
                                                                                                     ru.Elements <FieldChar>().FirstOrDefault(fc =>
                                                                                                                                              fc.FieldCharType == FieldCharValues.End)
                                                                                                     != null)
                                                                  != null) as Paragraph;
                if (pEnd == null)
                {
                    throw new ApplicationException("SetFormField: Did not find paragraph containing end.\r\n" + textInput.Parent.OuterXml);
                }
                rEnd = pEnd.Elements <Run>().FirstOrDefault(ru =>
                                                            ru.Elements <FieldChar>().FirstOrDefault(fc =>
                                                                                                     fc.FieldCharType == FieldCharValues.End)
                                                            != null);
            }

            // Remove any existing value.

            Run rFirst = rSeparate.NextSibling <Run>();

            if (rFirst == null || rFirst == rEnd)
            {
                RunProperties rPr = rTextInput.GetFirstChild <RunProperties>();
                if (rPr != null)
                {
                    rPr = rPr.CloneNode(true) as RunProperties;
                }
                rFirst = rSeparate.InsertAfterSelf <Run>(new Run(new[] { rPr }));
            }
            rFirst.RemoveAllChildren <Text>();

            Run r = rFirst.NextSibling <Run>();

            while (r != rEnd)
            {
                if (r != null)
                {
                    r.Remove();
                    r = rFirst.NextSibling <Run>();
                }
                else // next paragraph
                {
                    Paragraph p = rFirst.Parent.NextSibling <Paragraph>();
                    if (p == null)
                    {
                        throw new ApplicationException("SetFormField: Did not find next paragraph prior to or containing end.\r\n" + textInput.Parent.OuterXml);
                    }
                    r = p.GetFirstChild <Run>();
                    if (r == null)
                    {
                        // No runs left in paragraph, move other content to end of paragraph containing "separate" fieldchar.
                        p.Remove();
                        while (p.FirstChild != null)
                        {
                            OpenXmlElement oxe = p.FirstChild;
                            oxe.Remove();
                            if (oxe.GetType() == typeof(ParagraphProperties))
                            {
                                continue;
                            }
                            rSeparate.Parent.AppendChild(oxe);
                        }
                    }
                }
            }
            if (rEnd.Parent != rSeparate.Parent)
            {
                // Merge paragraph containing "end" fieldchar with paragraph containing "separate" fieldchar.
                Paragraph p = rEnd.Parent as Paragraph;
                p.Remove();
                while (p.FirstChild != null)
                {
                    OpenXmlElement oxe = p.FirstChild;
                    oxe.Remove();
                    if (oxe.GetType() == typeof(ParagraphProperties))
                    {
                        continue;
                    }
                    rSeparate.Parent.AppendChild(oxe);
                }
            }

            // Set new value.

            if (value != null)
            {
                // Word API use \v internally for newline and \r for para. We treat \v, \r\n, and \n as newline (Break).
                string[] lines = value.Replace("\r\n", "\n").Split(new char[] { '\v', '\n', '\r' });
                string   line  = lines[0];
                Text     text  = rFirst.AppendChild <Text>(new Text(line));
                if (line.StartsWith(" ") || line.EndsWith(" "))
                {
                    text.SetAttribute(new OpenXmlAttribute("xml:space", null, "preserve"));
                }
                for (int i = 1; i < lines.Length; i++)
                {
                    rFirst.AppendChild <Break>(new Break());
                    line = lines[i];
                    text = rFirst.AppendChild <Text>(new Text(lines[i]));
                    if (line.StartsWith(" ") || line.EndsWith(" "))
                    {
                        text.SetAttribute(new OpenXmlAttribute("xml:space", null, "preserve"));
                    }
                }
            }
            else
            { // An empty formfield of type textinput got char 8194 times 5 or maxlength if maxlength is in the range 1 to 4.
                short length = maxLength;
                if (length == 0 || length > 5)
                {
                    length = 5;
                }
                rFirst.AppendChild(new Text(((char)8194).ToString()));
                r = rFirst;
                for (int i = 1; i < length; i++)
                {
                    r = r.InsertAfterSelf <Run>(r.CloneNode(true) as Run);
                }
            }
        }