Использование расширений в карточке шаблона файла
Использование расширений в карточке шаблона файла¶
С помощью расширений можно воздействовать на результат, возвращаемый плейсхолдерами, а также изменить сам документ (изменить стиль, шрифт, форматирование текста документа).
В каждом сценарии расширения используется объект context, в котором, в зависимости от сценария, заполненые различные свойства (см. Расширения замены плейсхолдеров).
В сценариях Перед формированием документа/таблицы/строки
и Перед заменой плейсхолдера
предполагается инициализация необходимых данных, используемых в других сценариях, или изменения результатов замены плейсхолдера. Реализация данных сценариев по большей части общая для всех типов документов.
Примеры использования сценария Перед формированием документа
:
-
Инициализация параметров, которые могут быть использованы в других сценариях:
// Запись производится в context.Info, который является общим для всех выполняемых сценариев context.Info["MagicNumber"] = 42; context.Info["MagicWord"] = "Thanks";
-
Изменение значений всех определенных плейсхолдеров другими:
// Берем список всех не табличных плейсхолдеров, и для определенных плейсхолдеров подмениваем их результат var replacements = context.ReplacementContext.Replacements; for (int i = 0; i < replacements.Count; i++) { var replacement = replacements[i];
if (replacement.Placeholder.Value == "$Workplaces_User_MyTasks") { // Подмениваем старый объект IPlaceholderReplacement на новый с новым результатом replacements[i] = new PlaceholderReplacement( replacement.Placeholder, await context.GetPlaceholderValueAsync("$ApprovalHistory_ActiveTasks")); } }
Примеры использования сценария Перед формированием таблицы
:
-
Изменение значения конкретной колонки для каждой строки:
// Для каждой строки таблицы берем ее значения по определенной колонке и дописываем к ним magicNumber var magicNumber = context.Info.TryGet<int>("MagicNumber"); foreach(var row in context.Table.Rows) { var fields = row.TryGetFields("TaskInfo");
if (fields != null) { row["TaskInfo"] = fields .Select(x => new PlaceholderField(x.Value?.ToString() + magicNumber, x.DataType, x.Flags)) .ToList(); } }
-
Инициализация необходимых для обработки таблицы параметров (например, инициализация кастомного нумератора строк в таблице):
// Для таблицы записываем число строк в ней, чтобы использовать его как новый номер строки, но в обратном порядке var table = context.Table; table.Info["RowIndex"] = context.Table.Rows.Count;
Примеры использования сценария Перед формированием строки
:
-
Изменение значения конкретной колонки для текущей строки:
// Для текущей строки таблицы берем ее значения по определенной колонке и дописываем к ним magicWord var magicWord = context.Info.TryGet<string>("MagicWord"); var fields = context.Row.TryGetFields("TaskInfo");
if (fields != null) { context.Row["TaskInfo"] = fields .Select(x => new PlaceholderField(magicWord + x.Value?.ToString(), x.DataType, x.Flags)) .ToList(); }
-
Реализация кастомной нумерации внутри таблицы:
// Производим подмену значения, которое вернет плейсхолдер {n}, тем самым организовав обратную нумерацию строк в таблице // Инициализацию данного параметра следует проводить в сценарии Перед формированием таблицы if (!context.IsGroup) { var index = context.Table.Info.TryGet<int>("RowIndex"); var row = context.Row;
row.Number = index; context.Table.Info["RowIndex"] = index - 1; }
Примеры использования сценария Перед заменой плейсхолдера
:
-
Модификация результата плейсхолдера:
// Для заданных плейсхолдеров обновляем их результат if (context.Placeholder.Text == "{*t_role}") { context.PlaceholderValue = await context.GetPlaceholderValueAsync("tv:AuthorName"); } else if (context.Placeholder.Text == "{*t_result}") { context.PlaceholderValue = new PlaceholderValue("Комментарий: " + context.PlaceholderValue.Text, context.PlaceholderValue.Fields); }
В сцеанариях После формирования документа/таблицы/строки
и После замены плейсхолдера
предполагается постобработка уже сформированного результата. В зависимости от типа документа это может быть изменение самого текста результата, изменение стиля (цвет фона, цвет текста, стиль и шрифт текста). В зависимости от типа документа (.docx, .xlsx, .txt, .html) воздействия на результат производятся по разному.
Документ Word¶
При обработке документов Word в качестве параметра context
передается объект с типом WordPlaceholderReplaceExtensionContext
. Со всеми свойства данного контекста можно ознакомиться в API.
Для ознакомления с внутренней структурой документа Word рекомендуется использовать утилиту “Open XML SDK 2.5 Productivity Tool”.
Примеры использования сценария После замены плейсхолдера
:
-
Изменение фона ячейки определенных плейсхолдеров:
#using DocumentFormat.OpenXml.Wordprocessing;
// После замены заданного плейсхолдера, производим расчет просрочки задания и добавляем подсветку ячейки, в которой находился искомый плейсхолдер. // Аналогично подсветки ячеек в представлении "Мои задания" if (context.Placeholder.Text == "{*t_completed}") { var qn = await context.GetValueFromPlaceholderAsync<long>("tv:QuantsToFinish"); if (qn < 0) { var wordContext = context.As<WordPlaceholderReplaceExtensionContext>(); qn = Math.Max(-320, qn); var color = (255 + qn * 127 / 320).ToString("X");
var shading = new Shading() { Val = ShadingPatternValues.Clear, Color = "auto", Fill = "FF" + color + color, };
wordContext.PlaceholderElements[0].Parent.Parent.GetFirstChild<TableCellProperties>()?.Append(shading); } }
-
Изменение стиля текста для определенных плейсхолдеров:
#using DocumentFormat.OpenXml.Wordprocessing;
// Текст замененного плейсхолдера делаем жирным и подчеркнутым if (context.Placeholder.Text == "{*t_role}") { var wordContext = context.As<WordPlaceholderReplaceExtensionContext>(); Underline underline1 = new Underline(){ Val = UnderlineValues.Single }; Bold bold1 = new Bold();
foreach(var run in wordContext.PlaceholderElements) { var runProps = run.GetFirstChild<RunProperties>(); if (runProps == null) { runProps = new RunProperties(); run.InsertAt(runProps, 0); } runProps.Append(bold1); runProps.Append(underline1); } }
Примеры использования сценария После формирования строки
:
-
Изменение фона всей строки на зеленый цвет:
#using DocumentFormat.OpenXml.Wordprocessing;
// Производим смену цвета фона всех ячеек строки, если задание, по которому сформирована строка, не просрочена var qn = await context.GetValueFromPlaceholderAsync<long>("tv:QuantsToFinish"); if (qn >= 0) { var wordContext = context.As<WordPlaceholderReplaceExtensionContext>(); foreach(var cell in wordContext.CurrentRowElement.Elements<TableCell>()) { var greenShading = new Shading() { Val = ShadingPatternValues.Clear, Color = "auto", Fill = "92D050", }; cell.GetFirstChild<TableCellProperties>()?.Append(greenShading); } }
-
Изменение высоты строки таблицы:
#using DocumentFormat.OpenXml.Wordprocessing;
var rowProps = wordContext.CurrentRowElement.GetFirstChild<TableRowProperties>(); // Если в элементе текущей строки нет объекта TableRowProperties, то создаем его и добавляем в строку. // Элементы вида Properties должны находиться на первом месте внутри объекта. if (rowProps == null) { rowProps = new TableRowProperties(); wordContext.CurrentRowElement.InsertAt(rowProps, 0); }
// Высота рассчитывается в двадцатых частях от point. В свою очередь point - это 1/72 дюйма TableRowHeight tableRowHeight1 = new TableRowHeight(){ Val = (UInt32Value)20U * 40U }; // высота строки = 5/9 дюйма rowProps.Append(tableRowHeight1);
Примеры использования сценария После формирования таблицы
:
-
Изменение ширины таблиы и ее вырванивания в тексте:
#using DocumentFormat.OpenXml.Wordprocessing;
var wordContext = context.As<WordPlaceholderReplaceExtensionContext>();
var tableProps = wordContext.TableElement.GetFirstChild<TableProperties>(); var tableWidth = tableProps.GetFirstChild<TableWidth>(); var tableJustification = tableProps.GetFirstChild<TableJustification>();
if (tableJustification is null) { tableJustification = new TableJustification(); tableProps.Append(tableJustification); }
// Определяем, в чем мы будем рассчитывать ширину tableWidth.Type = TableWidthUnitValues.Pct;
// Задаем ширину в пятидесятых частях процента. tableWidth.Width = (50 * 80).ToString(); // 80%
tableJustification.Val = TableRowAlignmentValues.Center;
-
Изменение шрифта всего текста в таблице:
#using DocumentFormat.OpenXml.Wordprocessing;
var wordContext = context.As<WordPlaceholderReplaceExtensionContext>();
// Находим каждый элемент RunFonts в тексте и меняем шрифт в нем на нужным нам foreach(var fonts in wordContext.TableElement.Descendants<RunFonts>()) { fonts.Ascii = "Times New Roman"; fonts.HighAnsi = "Times New Roman"; fonts.ComplexScript = "Times New Roman"; fonts.EastAsia = "Times New Roman"; }
Примеры использования сценария После формирования документа
:
-
Установка заливки фона документа:
#using DocumentFormat.OpenXml.Wordprocessing; #using DocumentFormat.OpenXml.Vml; #using DocumentFormat.OpenXml.Vml.Office;
var wordContext = context.As<WordPlaceholderReplaceExtensionContext>();
// Генерация объекта фона DocumentBackground documentBackground1 = new DocumentBackground() { Color = "E2EFD9", ThemeColor = ThemeColorValues.Accent6, ThemeTint = "33" };
Background background1 = new Background() { Id = "_x0000_s1025", Fillcolor = "#e2efd9 [665]", BlackWhiteMode = BlackAndWhiteModeValues.White, TargetScreenSize = ScreenSizeValues.Sz1024x768 };
Fill fill1 = new Fill(){ Type = FillTypeValues.Gradient, Color2 = "fill lighten(0)", Method = FillMethodValues.Linearsigma };
background1.Append(fill1);
documentBackground1.Append(background1);
wordContext.Document.MainDocumentPart.RootElement.InsertAt(documentBackground1, 0);
// Установка информации, что используется фон wordContext.Document.MainDocumentPart.DocumentSettingsPart.Settings.DisplayBackgroundShape = new DisplayBackgroundShape();
Документ Excel¶
При обработке документов Excel в качестве параметра context
передается объект с типом ExcelPlaceholderReplaceExtensionContext
. Со всеми свойствами данного контекста можно ознакомиться в API.
Для ознакомления с внутренней структурой документа Excel рекомендуется использовать утилиту “Open XML SDK 2.5 Productivity Tool”.
Примеры использования сценария После замены плейсхолдера
:
-
Изменение фона ячейки определенных плейсхолдеров:
#using DocumentFormat.OpenXml.Spreadsheet;
var excelContext = context.As<ExcelPlaceholderReplaceExtensionContext>(); var stylesheet = excelContext.Document.WorkbookPart.WorkbookStylesPart.Stylesheet;
void UpdateCellStyle(Cell cell, long qn) { // Кешируем ID стиля в контекст по цвету, чтобы не генерировать кучу одинаковых стилей qn = Math.Max(-320, qn); var color = (255 + qn * 127 / 320).ToString("X"); if (!context.Info.TryGetValue("StyleID" + color, out var styleID)) { Fill fill1 = new Fill();
PatternFill patternFill1 = new PatternFill(){ PatternType = PatternValues.Solid }; ForegroundColor foregroundColor1 = new ForegroundColor(){ Rgb = "FF" + color + color }; BackgroundColor backgroundColor1 = new BackgroundColor(){ Indexed = (UInt32Value)64U };
patternFill1.Append(foregroundColor1); patternFill1.Append(backgroundColor1);
fill1.Append(patternFill1); stylesheet.Fills.Append(fill1); var fillID = stylesheet.Fills.Count() - 1;
var oldStyleID = cell.StyleIndex.Value; var newFormat = (CellFormat)stylesheet.CellFormats.ChildElements[Convert.ToInt32(oldStyleID)].CloneNode(true); newFormat.FillId = (UInt32Value)Convert.ToUInt32(fillID); newFormat.ApplyFill = true;
stylesheet.CellFormats.Append(newFormat); styleID = (UInt32Value)Convert.ToUInt32(stylesheet.CellFormats.Count() - 1); context.Info["StyleID" + color] = styleID; } cell.StyleIndex = (UInt32Value)styleID; }
if (context.Placeholder.Text == "{*t_completed}") { var qn = await context.GetValueFromPlaceholderAsync<long>("tv:QuantsToFinish"); if (qn < 0) { UpdateCellStyle(excelContext.Cell, qn); } }
-
Изменение стиля текста для определенных плейсхолдеров:
#using DocumentFormat.OpenXml.Spreadsheet;
// Текст замененного плейсхолдера делаем жирным и подчеркнутым if (context.Placeholder.Text == "{*t_role}") { // Т.к. у всех ячеек с данным плейсхолдером один и тот же стиль, генерируем новйы стиль один раз, а для остальных ячеек используем его if (!context.Info.TryGetValue("RoleStyleID", out var roleStyleID)) { var oldStyleID = excelContext.Cell.StyleIndex.Value; var newFormat = (CellFormat)stylesheet.CellFormats.ChildElements[Convert.ToInt32(oldStyleID)].CloneNode(true);
var oldFontID = newFormat.FontId.Value; var newFont = (Font)stylesheet.Fonts.ChildElements[Convert.ToInt32(oldFontID)].CloneNode(true);
newFont.Append(new Bold()); newFont.Append(new Underline());
stylesheet.Fonts.Append(newFont); newFormat.FontId = (UInt32Value)Convert.ToUInt32(stylesheet.Fonts.Count() - 1);
stylesheet.CellFormats.Append(newFormat); roleStyleID = (UInt32Value)Convert.ToUInt32(stylesheet.CellFormats.Count() - 1); context.Info["RoleStyleID"] = roleStyleID; }
excelContext.Cell.StyleIndex = (UInt32Value)roleStyleID; }
Примеры использования сценария После формирования строки
:
-
Изменение фона всей строки на зеленый цвет:
#using DocumentFormat.OpenXml.Spreadsheet;
var excelContext = context.As<ExcelPlaceholderReplaceExtensionContext>(); var stylesheet = excelContext.Document.WorkbookPart.WorkbookStylesPart.Stylesheet;
void UpdateRowStyle(Row row) { // Цвет строки задается через цвета ее ячеек. // У каждой колонки может быть свой стиль, рассчитываем стили для каждой ячейки один раз и кешируем идентификатор стиля foreach(var cell in row.Elements<Cell>()) { if (!context.Info.TryGetValue("RowStyleID" + cell.CellReference.Value[0], out var styleID)) { Fill fill1 = new Fill();
PatternFill patternFill1 = new PatternFill(){ PatternType = PatternValues.Solid }; ForegroundColor foregroundColor1 = new ForegroundColor(){ Rgb = "92D050" }; BackgroundColor backgroundColor1 = new BackgroundColor(){ Indexed = (UInt32Value)64U };
patternFill1.Append(foregroundColor1); patternFill1.Append(backgroundColor1);
fill1.Append(patternFill1); stylesheet.Fills.Append(fill1); var fillID = stylesheet.Fills.Count() - 1;
var oldStyleID = cell.StyleIndex.Value; var newFormat = (CellFormat)stylesheet.CellFormats.ChildElements[Convert.ToInt32(oldStyleID)].CloneNode(true); newFormat.FillId = (UInt32Value)Convert.ToUInt32(fillID); newFormat.ApplyFill = true;
stylesheet.CellFormats.Append(newFormat); styleID = (UInt32Value)Convert.ToUInt32(stylesheet.CellFormats.Count() - 1); context.Info["RowStyleID" + cell.CellReference.Value[0]] = styleID; } cell.StyleIndex = (UInt32Value)styleID; } }
// Производим сменц цвета фона всех ячеек строки, если задание, по которому сформирована строка, не просрочена var qn = await context.GetValueFromPlaceholderAsync<long>("tv:QuantsToFinish"); if (qn >= 0) { UpdateRowStyle(excelContext.CurrentRowElement); }
-
Изменение высоты строки таблицы:
// Высота задается в point, который равен 1/72 дюйма excelContext.CurrentRowElement.Height = 40D; // 5/9 дюйма
Примеры использования сценария После формирования таблицы
:
-
Изменение ширины колонок в листе, где располагается таблица:
#using DocumentFormat.OpenXml.Spreadsheet;
var excelContext = context.As<ExcelPlaceholderReplaceExtensionContext>(); var columns = excelContext.Worksheet.GetFirstChild<Columns>();
foreach(Column column in columns.ChildElements) { // Изменяем ширину для первых 5 колонок. Нумерация колонок ведется с 1 if (column.Min.Value > 0U && column.Max.Value <= 5U) { column.Width = 40D; } }
Примеры использования сценария После формирования документа
:
-
Изменение шрифта текста документа:
#using DocumentFormat.OpenXml.Spreadsheet;
var excelContext = context.As<ExcelPlaceholderReplaceExtensionContext>(); var stylesheet = excelContext.Document.WorkbookPart.WorkbookStylesPart.Stylesheet;
// Задаем каждому объекту Font нужный шрифт foreach(Font font in stylesheet.Fonts.ChildElements) { font.FontName = new FontName(){ Val = "Times New Roman" }; font.FontFamilyNumbering = new FontFamilyNumbering(){ Val = 2 }; }
// Указываем каждому стилю, что нужно применить шрифт, указанный в стиле foreach(CellFormat style in stylesheet.CellFormats.ChildElements) { style.ApplyFont = true; }