This post includes a series of interesting support tickets answered throughout October and November along with a handful of enhancements made to our Office-inspired product line. We hope you find the contents of this post interesting and of business value. Should you have any questions about this post, feel free to comment below.
Breaking Change in .NET 6
As you may already know, Microsoft changed DeflateStream, GZipStream, and CryptoStream behaviors in .NET 6. See the following breaking change for more information: DeflateStream, GZipStream, and CryptoStream handling of partial and zero-byte reads.
This breaking change affects our Office File API and Office-inspired UI controls (for WinForms and WPF) as we use DeflateStream to import OpenXML documents and load data from ZIP archives. If your application targets .NET 6, you may encounter the following issues:
- Your Word (DOCX, DOTX, DOCM, or DOTM) and Excel (XLSX, XLSM, XLTX, or XLTM) documents may be loaded incorrectly.
- The
ZipItem.Extract
method can throw CrcErrorArchiveItemException.
Please upgrade to v21.1.7+ or v21.2.4+ to avoid/address these issues within your .NET 6 project (see Bug Report T1047593).
Tips & Tricks
WinForms and WPF Rich Text Editors
T1034579 - How to use a shortcut to move focus from the WPF Rich Text Editor to the next control
https://supportcenter.devexpress.com/ticket/details/t1034579T1035369 - How to hide the Quick Access Toolbar on the WPF Rich Text Editor's ribbon
https://supportcenter.devexpress.com/ticket/details/t1035369T1037807 - How to specify decimal point position in the MERGEFIELD field independently from the current locale's number format
https://supportcenter.devexpress.com/ticket/details/t1037807Use the RichEditMailMergeOptions.CustomSeparators property to define custom separators instead of separators specific to the current locale.
The code sample below demonstrates how to specify custom decimal separators for field code and field result.
using DevExpress.XtraRichEdit; using DevExpress.XtraRichEdit.API.Native; // ... using (var wordProcessor = new RichEditDocumentServer()) { // Access a document. Document document = wordProcessor.Document; // Specify the custom decimal separator for the field code. wordProcessor.Options.MailMerge.CustomSeparators.MaskDecimalSeparator = "."; // Specify the custom decimal separator for the field result. wordProcessor.Options.MailMerge.CustomSeparators.FieldResultDecimalSeparator = "."; // Create the "MERGEFIELD" field. document.Fields.Create(document.Range.Start, @"MERGEFIELD Amount \# 0.00 "); // Merge the document. wordProcessor.Document.MailMerge("output.docx", DocumentFormat.OpenXml); }
T1045550 - How to implement syntax highlighting for XML text
https://supportcenter.devexpress.com/ticket/details/t1045550T1046699 - How to use custom painting to highlight words in a paragraph
https://supportcenter.devexpress.com/ticket/details/t1046699
WinForms and WPF Spreadsheet Controls
T1034923 - How to display a message that prompts a user to save changes before the current spreadsheet document is closed
https://supportcenter.devexpress.com/ticket/details/t1034923Handle the
SpreadsheetControl.DocumentClosing
event and use theSpreadsheetControl.Modified
property within the event handler to check whether the current document has changes. We use this method in our demos for the WinForms and WPF Spreadsheet controls. The following code snippet from our demos demonstrates how to display a prompt message before the document is closed:void spreadsheetControl1_DocumentClosing(object sender, CancelEventArgs e) { if (spreadsheetControl1.Modified) { string currentFileName = spreadsheetControl1.Options.Save.CurrentFileName; string message = !string.IsNullOrEmpty(currentFileName) ? $"Do you want to save the changes you made for '{currentFileName}'?" : "Do you want to save the changes?"; DialogResult result = XtraMessageBox.Show(message, "Warning", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning); if (result == DialogResult.Yes) { e.Cancel = !spreadsheetControl1.SaveDocument(); } else e.Cancel = result == DialogResult.Cancel; } }
T1036481 - How to create total bars for a Waterfall chart via the Spreadsheet control’s UI
https://supportcenter.devexpress.com/ticket/details/t1036481T1038552 - How to exclude chart types from the Insert Chart ribbon menu in the WPF Spreadsheet control
https://supportcenter.devexpress.com/ticket/details/t1038552T1039579 - How to exclude chart types from the Change Chart Type dialog in the WPF Spreadsheet control
https://supportcenter.devexpress.com/ticket/details/t1039579T1045409 - How to keep hidden columns invisible when the AutoFitColumns method is executed
https://supportcenter.devexpress.com/ticket/details/t1045409Create a union range with only visible columns and call the AutoFitColumns extension method for this range.
private static void AutoFitVisibleColumns(Worksheet worksheet, int startColumn, int endColumn) { var range = worksheet.Range.FromLTRB(startColumn, 0, endColumn, 0); for (int i = startColumn; i <= endColumn; i++) { if (!worksheet.Columns[i].Visible) range = range.Exclude(worksheet.Columns[i]); } range.AutoFitColumns(); }
T1045447 - How to prevent export of filtered rows when a document is saved in XLSX or XLS format
https://supportcenter.devexpress.com/ticket/details/t1045447Iterate through worksheet rows and check the Row.Visible and Row.IsFiltered properties. If a row is hidden and belongs to a filtered range, call the Worksheet.Rows.Remove method to delete this row from the worksheet.
spreadsheetControl.BeginUpdate(); CellRange dataRange = worksheet.GetDataRange(); int rowCount = 0; int lastRowIndex = dataRange.BottomRowIndex; for (int rowIndex = lastRowIndex; rowIndex >= 0; rowIndex--) { Row row = worksheet.Rows[rowIndex]; if (!row.Visible && row.IsFiltered) rowCount++; else { if (rowCount > 0) worksheet.Rows.Remove(rowIndex + 1, rowCount); rowCount = 0; } } if (rowCount > 0) worksheet.Rows.Remove(0, rowCount); spreadsheetControl.EndUpdate(); spreadsheetControl.SaveDocument("Result.xlsx", DocumentFormat.Xlsx);
WinForms PDF Viewer
T1041459 - How to expand all comments when the Comment page is selected in the Navigation Pane
https://supportcenter.devexpress.com/ticket/details/t1041459Handle the PdfViewer.NavigationPaneSelectedPageChanged event and execute the PdfCommentTreeExpandAllCommand command within the event handler when the Comments page is selected.
private void PdfViewer_NavigationPaneSelectedPageChanged(object sender, DevExpress.XtraPdfViewer.PdfNavigationPaneSelectedPageChangedEventArgs e) { if(e.SelectedPage == DevExpress.XtraPdfViewer.PdfNavigationPanePage.Comments) { PdfCommentTreeExpandAllCommand command = new PdfCommentTreeExpandAllCommand(pdfViewer); command.Execute(); } }
T1046234 - How to drag-and-drop a signature field in the PDF Viewer
https://supportcenter.devexpress.com/ticket/details/t1046234T1040660 - How to remove space between pages in the PDF Viewer
https://supportcenter.devexpress.com/ticket/details/t1040660
WinForms Spell Checker
T1034525 - How to use the check-as-you-type mode to check spelling in read-only text editors
https://supportcenter.devexpress.com/ticket/details/t1034525
Enhancements
Spreadsheet Document API and Spreadsheet Controls (for WinForms and WPF)
T1042763 - We implemented new API properties that allow you to link shape text to a cell
https://supportcenter.devexpress.com/ticket/details/t1042763You can now use the
Shape.ShapeText.Formula
property to specify a reference to the cell that contains text you want to display in your shape. Use the A1 or R1C1 cell reference type depending on reference style used in your workbook (see DocumentSettings.R1C1ReferenceStyle). External references are not supported.// Specify cell value. worksheet["B2"].Value = "Shape Text"; // Create rectangle. var rectangle = worksheet.Shapes.AddShape(ShapeGeometryPreset.Rectangle, worksheet["B4:D7"]); // Link shape text to the "B2" cell. rectangle.ShapeText.Formula = "=Sheet1!B2";
The following image demonstrates the result:
You can also use a defined name that refers to the required cell.
// Specify cell value. worksheet["B2"].Value = "Shape Text"; // Create defined name for the "B2" cell. worksheet.DefinedNames.Add("cellB2", "Sheet1!$B$2"); // Create rectangle. var rectangle = worksheet.Shapes.AddShape(ShapeGeometryPreset.Rectangle, worksheet["B4:D7"]); // Use defined name to link shape text to the "B2" cell. rectangle.ShapeText.Formula = "=cellB2";
The
Shape.ShapeText.IsLinked
property returns true if shape text is linked to a cell. Shape text is updated automatically when a value in the referenced cell changes or document formulas are recalculated.T1041398 - We added a new WorksheetView.GridlineColor property to specify the color of worksheet gridlines
https://supportcenter.devexpress.com/ticket/details/t1041398The following code snippet changes the gridline color to red:
workbook.Worksheets[0].ActiveView.GridlineColor = Color.Red;
Assign Color.Empty to the
WorksheetView.GridlineColor
property to restore default gridline color. Transparent or semitransparent colors are not supported.
PDF Document API
T1037054 - We implemented a new PdfDocumentProcessor.DataRecognitionCacheSize property that allows you to set cache size (in pages) for data recognition
https://supportcenter.devexpress.com/ticket/details/t1037054Use the
PdfDocumentProcessor.DataRecognitionCacheSize
property to increase the number of pages with cached data. This may be useful if you need to accelerate FindText method execution on documents larger than 65 pages (the default cache size is 65 pages).If the DataRecognitionCacheSize property is set to 0, cache size is unlimited.
pdfDocumentProcessor.DataRecognitionCacheSize = 100;
T1047842 – We added new APIs to create a form field with multiple widgets
https://supportcenter.devexpress.com/ticket/details/t1047842You can now add widgets to a text box (PdfAcroFormTextBoxField), check box (PdfAcroFormCheckBoxField), and list box/combo box (the PdfAcroFormChoiceField class descendants).
Use the following methods to manage a form field’s widgets:
AddWidget(PdfRectangle rectangle)
Adds a widget to the page where the form field is located.
AddWidget(int pageNumber, PdfRectangle rectangle)
Adds a widget to a specific page.
ClearWidgets()
Removes existing widgets from the form field.
We also implemented a new
AddButton(string name, int pageNumber, PdfRectangle rect)
method for the PdfAcroFormRadioGroupField class to append an additional radio button to a radio group field.
WinForms and WPF PDF Viewers
T1035241 - We added a PdfViewer.CommitFormFieldEditorValue method to commit the active form field's value before a user moves focus to another form field (using the keyboard or mouse)
https://supportcenter.devexpress.com/ticket/details/t1035241T1024770 – We added an AnnotationChanging event to cancel editing annotations
https://supportcenter.devexpress.com/ticket/details/t1024770
https://supportcenter.devexpress.com/ticket/details/t1051202Set the
PdfAnnotationChangingEventArgs.Cancel
parameter to true to cancel annotation editing.private void PdfViewer_AnnotationChanging(object sender, PdfAnnotationChangingEventArgs e) { if (e.OldAnnotation.Author != author) { e.Cancel = true; } }
T1034968 - You can now use the PDF Facade API to set flags for form field widgets
https://supportcenter.devexpress.com/ticket/details/t1034968The following code snippet demonstrates how to prohibit printing interactive form fields:
var documentFacade = pdfViewer1.GetDocumentFacade(); var fields = documentFacade.AcroForm.GetFields(); foreach(PdfWidgetFacade pdfWidget in fields.SelectMany(f => f)) { pdfWidget.Flags &= ~PdfAnnotationFlags.Print; }
1046933 – You can now use the PDF Facade API to set annotation flags
https://supportcenter.devexpress.com/ticket/details/t1046933The following code snippet demonstrates how to prohibit printing annotations:
foreach (var page in documentFacade.Pages) foreach (var annotation in page.Annotations) annotation.Flags &= ~PdfAnnotationFlags.Print;
Note: Add the DevExpress.Docs.v21.2.dll assembly to your project to use the PDF Facade API. Please note that you need an active DevExpress Office File API Subscription or DevExpress Universal Subscription to use this assembly in production code.
New Examples: WinForms and WPF Spreadsheet Controls
We created two examples that demonstrate the use of the DevExpress Spell Checker component (to check spelling in our WinForms and WPF Spreadsheet controls). When a user enters text in a cell, the spell checker indicates misspelled words with a red wavy line. A user can right-click an underlined word and select the correct spelling from the list of suggestions or invoke the Spelling dialog.
- WinForms Spreadsheet - Spell Check Text in a Cell Editor
- WPF Spreadsheet - Spell Check Text in a Cell Editor
Your Feedback Matters
As always, if you’ve come across an interesting support ticket you’d like to share with the rest of the DevExpress developer community, please comment below and include the appropriate link.