In This Article

Converting to v26.1

The 26.1 version made a number of infrastructure updates and improvements.

.NET Targets Changes

.NET 6 and 7 are out of support, so targets for net6.0 and net6.0-windows have been removed. Windows-based projects must target .NET 8 or higher.

This release adds new targets for net10.0 and net10.0-windows.

Nullable Reference Type (NRT) Annotations

This release adds full nullable reference type annotations to the public API. These annotations improve static analysis and help callers understand when values may be null. Existing behavior is unchanged at runtime, but you may see new compiler warnings when upgrading. Review your code for null‑safety where needed.

Every attempt should be made to avoid warnings that are flagged by static code analysis, but do not be discouraged if a lot of warnings are displayed for existing code after the upgrade. Just because something can be null does not mean it will be null. For example, several class properties that are not normally null still had to be flagged at nullable just because the property or its backing field were set to null when disposed.

Even though there may not be issues, we strongly encourage all warnings to be researched and addressed as soon as possible to avoid throwing NullReferenceException at run-time.

Tip

If your environment is configured to treat warnings as errors, you may want to temporarily disable that configuration and resolve all true errors before addressing the nullable-aware changes.

IURenderer Null Properties

To simplify working with reference type properties on instances of IUIRenderer (such as BackgroundFill, Border, or Font), all properties for reference types will be nullable even if the default value is not null.

Previously, some properties supported null values and others did not. Thanks to the added security of nullable static code analysis, we were able to update all built-in renderers to handle null values and can confidently remove the non-null restriction.

Any custom implementations of a IUIRenderer should be updated to handle possible null references to any BackgroundFill, Border, or Font property values.

Licensing Updates

The licensing infrastructure and the license dialog have been refactored and improved in this version. The license dialog now has a simpler design that makes it easier to understand what triggered the dialog display and allows copying of that information for submission to Actipro support when needed. Licensing-related types have been moved to the new ActiproSoftware.Licensing namespace.

RegisterLicense Calls

Any calls to the ActiproLicenseManager.RegisterLicense method need their namespace changed to avoid this this compile error:

error CS0234: The type or namespace name 'ActiproLicenseManager' does not exist in the namespace 'ActiproSoftware.Products'
Important

Change the namespace by updating ActiproSoftware.Products.ActiproLicenseManager.RegisterLicense(...) calls to ActiproSoftware.Licensing.ActiproLicenseManager.RegisterLicense(...).

The old RegisterLicense method had two overloads. One overload allowed for an AssemblyInfo to be specified when the license information being set only applied to a single product. This is useful for an app plugin that uses Actipro controls, so that it won't interfere with any other license registration calls made by the app itself, or other plugins. In the new API, there is a single RegisterLicense method, but the AssemblyInfoBase parameter is optional at the end. Leave it null to register a single license for all used Actipro products, which is the default usage scenario.

Licenses.licx Files

If the older licenses.licx way of licensing is used (classic .NET Framework apps only), the token type referenced in the licenses.licx file entry needs its namespace changed.

Important

Change the namespace by updating the ActiproSoftware.Products.ActiproLicenseToken, ... line to ActiproSoftware.Licensing.ActiproLicenseToken, ....

Tip

This may be a good time to convert over to the RegisterLicense way of licensing from the older licenses.licx way of licensing. Please see the Licensing topic for more information on converting.

Licenses.licx Assembly Scanning Logic Changes

In the past when looking for stored license information in an assembly context, the licensing logic would scan the entry (application) assembly first, then any hint assemblies (via ActiproLicenseManager.AddHintAssemblyName calls), and finally all assemblies in the app domain. Since licensing is migrating more towards RegisterLicense calls and away from licenses.licx files, we simplified this logic to exclude the final step of scanning all assemblies in the app domain. From now on, when using licenses.licx licensing, if the licenses.licx file is not in the entry (application) assembly, you must use an ActiproLicenseManager.AddHintAssemblyName call to designate an additional assembly to examine.

Important

If you use licenses.licx licensing, check the deployment of your app on a clean end user machine to verify licensing is working as intended after making necessary changes.

Core Library

A new Core library has been added in this version to contain fundamental classes used throughout our product line, and all the Actipro assemblies reference it. A number of core types used throughout our UI and non-UI assemblies have been migrated into this new Core library.

Important

If your application uses assembly references to Actipro products, you must add a reference to the ActiproSoftware.Core.WinForms.dll assembly to ensure that all Actipro types are properly resolved. Customers using Actipro's NuGet packages for references will not need to make any changes.

ObservableObjectBase Migrated

The ObservableObjectBase class was moved from its previous namespace ActiproSoftware.UI.WinForms to the Core library in the ActiproSoftware namespace. The class now implements both the IPropertyChanging and IPropertyChanged interfaces.

The older implementation of the class used a NotifyPropertyChanged method to notify of property changes. A new SetProperty method replaces that method and performs these tasks:

  • Checks for equality between the existing backing field value and the new value being set. The method return value is true if the value was changed.
  • Raises the PropertyChanging event.
  • Updates the field value with the new value.
  • Raises the PropertyChanging event.

This code shows how a class that inherits ObservableObjectBase can use the SetProperty method to update the backing field and raise events:

public class WindowModel : ObservableObjectBase {

	private bool _canClose;

	public bool CanClose {
		get => _canClose;
		set => SetProperty(ref _canClose, value);
	}
}
Tip

Migrate any prior ObservableObjectBase usage to the ObservableObjectBase class in the Core library. Update any usage of the NotifyPropertyChanged method to the new SetProperty method.

For any scenarios where updating a backing field is not required, call the OnPropertyChanged method instead of the NotifyPropertyChanged method.

To ensure a consistent API, all classes that implement INotifyPropertyChanged that do not derive from ObservableObjectBase have also deprecated the NotifyPropertyChanged method in favor of new OnPropertyChanged and SetProperty methods that match ObservableObjectBase.

DisposableObjectBase Migrated

The DisposableObjectBase class was renamed from DisposableObject in its previous namespace ActiproSoftware.Text.Utility and moved to the Core library in the ActiproSoftware namespace. Its Dispose method is now abstract instead of being virtual with an empty implementation.

The Shared library's former DisposableObject class was renamed to MarshalByRefDisposableObject, since that class inherited MarshalByRefObject.

Tip

Migrate any prior DisposableObject usage to the DisposableObjectBase class in the Core library.

DoubleExtensions Migrated

The DoubleExtensions class from moved from its previous ActiproSoftware.UI.WinForms.Extensions namespace to the Core library in the ActiproSoftware.Extensions namespace.

Some methods were renamed:

Tip

Migrate any prior extension method usage to the extension methods in the ActiproSoftware.Extensions namespace in the Core library.

WeakEventListener Class Migrated

The WeakEventListener<T,U> class, not commonly used outside of Actipro-written code, was moved to the Core library in the ActiproSoftware namespace.

Logging Types Namespace Changes

The logging-related types in the ActiproSoftware.Products.Logging namespace, not commonly used outside of Actipro-written code, have been moved to the Core library in the ActiproSoftware.Logging namespace.

Tip

Find ActiproSoftware.Products.Logging and replace with ActiproSoftware.Logging to convert any references to affected types.

SyntaxEditor

This release includes several fundamental changes to the SyntaxEditor product. Most changes are breaking and will result in compiler errors until they are resolved, but others, like line terminator processing, will not be exposed by the compiler. The following summaries the changes in this release, and each concept is explained in more detail below:

  • Various structures have replaced special "deleted" or "empty" concepts with nullable values instead. Some have also been streamlined or updated.
  • Line terminators are now preserved instead of normalized to line feeds.
  • Several types renamed to fix "mergable" misspelling.
  • The PlainText syntax language is now a shared instance.
  • DisplayItemClassificationTypeProvider merged into BuiltInClassificationTypeProvider.
  • AstNodeBase.Children changed from IList<IAstNode> to IEnumerable<IAstNode>.
  • ITextBufferReader split into two interfaces with several members renamed for clarity.
  • Several types moved to new Core assembly.

Refactoring of How Various Structures Implement Deleted and Empty Concepts

Past versions of SyntaxEditor had important structures with special properties to indicate if they were "deleted" or "empty". Part of v26.1 SyntaxEditor refactoring involved removing those properties and moving to a modern nullable concept instead. The benefit of this is that the compiler can warn when possible "deleted" or "empty" values are returned, forcing better code to be written.

Modified Structures and Their Original Properties

This list provides details on the structures that were modified as part of the update and how their now-removed properties behaved.

  • Range struct
    • Empty property returned a -1, -1 pair of offsets.
    • IsEmpty property returned if the range was a -1, -1 pair.
  • TextBounds struct
    • Empty property was based on the bounds of Rectangle.Empty and IsRightToLeft of false.
    • IsEmpty property returned if the Width was less than 0.
  • TextPosition struct
    • Empty property returned a -1, -1 pair of line/char.
    • IsEmpty property returned if the line/char was a -1, -1 pair.
  • TextPositionRange struct
    • Empty property returned an Empty, Empty pair of TextPosition objects.
    • IsEmpty property returned if the TextPosition objects were an Empty, Empty pair.
  • TextRange struct
    • Deleted property returned a -1, -1 pair of offsets.
    • IsDeleted property returned if the range was a -1, -1 pair.
  • TextSnapshotOffset struct
    • Deleted property returned a null snapshot and -1 offset.
    • IsDeleted property returned if the struct had a null snapshot or negative offset.
  • TextSnapshotRange struct
    • Deleted property returned a null snapshot and TextRange.Deleted.
    • IsDeleted property returns if the struct had a null snapshot or TextRange.Deleted.

After the code updates, a null value indicates a "deleted" or "empty" state for the structures above. For instance, a variable that is declared with type TextRange? (effectively Nullable<TextRange>) will be non-null when it has valid values and will be null when it is considered deleted.

Breaking Changes

The following list of breaking changes were made for this update.

.NET Languages Add-on
Web Language Add-on
Python Language Add-on

Checking for Valid Values

In cases where a nullable result is now in a return value, use a HasValue check to see if a value is provided, and the Value property to access the value if it is there.

public void PrintParseError(IParseError error) {
	if (error.PositionRange.HasValue)
		Debug.WriteLine($"Error at {error.PositionRange.Value}");
}

Line Terminator Updates

Past versions of SyntaxEditor would normalize all document text to a single character LF (line feed or "\n") only. This made lexing, parsing, and other operations more efficient since it avoided the need for complex logic to watch for possible two-character line terminators like CRLF ("\r\n"). Overloads for document snapshot methods like GetText and GetSubstring allowed you to convert the line terminators back to CRLF form, or something else if desired. All offsets were consistent zero-based integers relative to the document character positions where LF-only was used for line terminators.

While this has worked for many years, there are some cases where this behavior is not ideal. For instance, if an offset is provided by an external source for CRLF line terminated document text, the offset would not be the same as the SyntaxEditor document offsets, due to the normalization of CRLF into LF within SyntaxEditor. When opening a file, it's always helpful to know if the document text has consistent line terminators throughout, and if so, what they are. The application may wish to display the document's line terminator kind in a status bar, or show "Mixed" when multiple line terminators are used, and allow the document text to be normalized to another line terminator kind. These are some of the reasons that we decided to overhaul the internals of how SyntaxEditor processes line terminators for v26.1.

No More LF Normalization

SyntaxEditor will no longer normalize document text to LF-only line terminators, and instead will now retain whatever line terminator was used when opening a file. If an opened file had CRLF line terminators, the document text will now have a CR ("\r") character followed by a LF ("\n") character at each line terminator. Other single character line terminators and even a mix of multiple line terminators are supported.

The LineTerminator enumeration has been updated with all the supported line terminators:

  • CRLF ("\r\n") - Carriage return and line feed sequence. This format is typically used on Windows machines.
  • LF ("\n") - Line feed. This format is typically used on UNIX and macOS machines.
  • CR ("\r") - Carriage return. Not commonly used.
Important

Any custom document character-scanning logic such as in a programmatic lexer or parser must be updated to support all line terminator characters now, and possible CRLF sequences.

Note

A new ExperimentalFeatures.AllLineTerminatorsPreserved property that defaults to true has been added. Set this property to false to force line terminators to be normalized to LF within document snapshots.

Runtime Regular Expression Searching

Regular expression searching used to find line terminators with \n only. Now that multiple kinds of line terminators can be present in document text, regular expression searching must specify the line terminator characters present in document text for matches to be made.

LineTerminator Member Name Updates

These original LineTerminator values are still present, but have been deprecated and map over to the newer, shorter related values. Update your code to switch to the new values:

  • CarriageReturnNewline - Use CRLF instead.
  • Newline - Use LF instead.
  • CarriageReturn - Use CR instead.

Document Snapshot Line Terminator Uniformity

The ITextSnapshot.HasUniformLineTerminators property returns whether all of the line terminators in the document snapshot are the same. When this property returns false, the line terminators are considered mixed.

Document Snapshot Inferred Line Terminator

The ITextSnapshot.InferredLineTerminator property returns a LineTerminator value indicating which line terminator should be used in the document. The value returned is based on what is identified in the document text.

In the case of mixed line terminators, priority is given to line terminators in the order of the list above. A document with one CRLF line terminator and two LF line terminators in its text will return CRLF as the inferred line terminator, since the presence of any CRLF has a higher priority than LF.

When a document is empty, there are no line terminators from which to infer a result. The system's line terminator via Environment.NewLine will be used to infer a result in that case.

Dynamic Lexer Line Terminator Matching

An IDynamicLexer.CanLineFeedMatchAnyLineTerminator property was added with a default of true to allow \n specifications to match any line terminator and minimize breaking changes with previous versions. Change it to false to only match LF with \n.

Breaking Changes

The following list of breaking changes were made for this update.

  • ITextDocument
    • LoadFile method no longer returns a LineTerminator. Use the new InferredLineTerminator property from the document's current snapshot following load instead.
    • SaveFile method now has an optional LineTerminator argument that should only be specified when line ends should be normalized to a certain line terminator in the saved file.
  • ITextExporter.LineTerminator property now is nullable, where the default null value means to use the inferred line terminator from the source snapshot.
  • ITextSnapshot
    • GetSubstring methods now have an optional LineTerminator. If left null, the default, no line end normalization will take place.
    • GetText method now has an optional LineTerminator. If left null, the default, no line end normalization will take place.
    • Text property effectively calls GetText(null), returning text without any sort of line terminator normalization, whereas the property used to normalize to CRLF line terminators.
  • ITextViewLine.Text property no longer normalizes any contained line terminators to LF.
  • ITokenReader.GetTokenText method no longer normalizes line terminators to LF.
  • LineTerminator enum updated with shorter value names and additional values. Old longer value names are retained temporarily, but are obsolete and should be replaced with the newer shorter names. The type has moved to Core assembly.

Mergeable Misspelling Fix

Numerous lexer-related types in SyntaxEditor were originally misspelled with the name "mergable" (not a word) instead of the proper word "mergeable". This originated due to .NET itself having a System.ComponentModel.MergablePropertyAttribute class, and us going with that term assuming it was correct spelling when adding our own classes. After release, we realized that it wasn't a proper spelling of the word, however we avoided making any changes to correct it since it would lead to multiple breaking changes.

Years later and as we deep dive into making some core SyntaxEditor infrastructure improvements, we feel that v26.1 is an appropriate time to correct the instances of the misspelled word. All types, members, comments, and documentation have been updated to the proper spelling in this version.

Important

This set of updates will cause compilation errors in any code that references the term "mergable", such as type or member not found errors. The simplest way to migrate code is to do a solution-wide search for "ergable" and replace it with "ergeable" where appropriate.

Be careful not to update any usage of .NET's MergablePropertyAttribute, since that will continue to use the misspelled term.

The following types and members have been affected by this update:

SyntaxLanguage.PlainText Updates

The SyntaxLanguage.PlainText property previously created a new instance of an empty SyntaxLanguage each time it was called. However, it is better design to have properties return a cached instance instead.

In this version, the property now returns a cached instance. This means that if you add language services to the SyntaxLanguage.PlainText instance, the same services will appear on any other document language that was previously assigned from that property. This can be useful in scenarios where you may wish to assign a custom IWordBreakFinder or other service for plain text.

Note that CodeDocument instances continue to be assigned a new syntax language instance that is not the value returned by the SyntaxLanguage.PlainText property.

DisplayItemClassificationTypeProvider Merged into BuiltInClassificationTypeProvider

Previous versions had two predefined classification type provider classes that would register known classification types with default styles in a target highlighting style registry:

In this version, DisplayItemClassificationTypeProvider has been merged into BuiltInClassificationTypeProvider. Simply replace code references from the one type to the other to convert.

Note

The BuiltInClassificationTypeProvider.RegisterAll method now registers all classification types previously registered by the separate two types. Whereas the new RegisterLanguageTextItems method only registers language text items (keyword, comment, string, etc.) and the new RegisterDisplayItems method registers everything else (errors, selection, margin-related, etc.). Use of one of those two methods instead of the RegisterAll method may be warranted at times.

AstNodeBase.Children Updates

In previous versions, the AstNodeBase.Children property created a new List<IAstNode> on each invocation when child AST nodes were present. This was not efficient, especially when callers may have assumed that the list had been a cached list, and had referenced the property repeatedly.

In this version, the property has been updated to return IEnumerable<IAstNode> instead of IList<IAstNode>, and the AST nodes returned from the property are yielded. This improves performance for many scenarios where simple enumeration is required, and even moreso when the enumeration doesn't require examination of all child AST nodes.

Some scenarios are more efficient when working with an IList<IAstNode>, such as when needing to know the total count of items and also using an indexer to get certain items. In these scenarios, use LINQ's ToList() extension method to create an IList<IAstNode> with which you can work.

Basic Structure Changes

Several core structures have been streamlined or updated.

TextPosition Updates

TextPosition has had these members updates:

  • Equals, CompareTo, and GetHashCode methods - Comparison logic now includes the HasFarAffinity property value. A new CompareToWithoutAffinity method was added to do comparisons without consideration of HasFarAffinity, similar to how CompareTo previously behaved.

TextRange Updates

TextRange is now a read-only struct and has had these members updated:

  • Invert method - Removed since cannot be used with a read-only struct.
  • Normalize method - Removed since cannot be used with a read-only struct. Callers can use range = range.Normalized to accomplish the same behavior.
  • NormalizedTextRange property - Replaced by the new shorter-named Normalized property.

In addition, TextRange no longer implements ITextRangeProvider itself.

TextPositionRange Updates

TextPositionRange is now a read-only struct and has had these members updated:

  • Invert method - Removed since cannot be used with a read-only struct.
  • Normalize method - Removed since cannot be used with a read-only struct. Callers can use range = range.Normalized to accomplish the same behavior.
  • NormalizedTextPositionRange property - Replaced by the new shorter-named Normalized property.

TextSnapshotRange Updates

TextSnapshotRange has had these members updated:

  • AbsoluteLength property - Flagged obsolete and will be removed in the future since snapshot ranges are always normalized. Use the Length property instead, which always returns a non-negative length already.
  • OverlapsWith method - The overload with a TextSnapshotRange parameter will now throw an exception if the two snapshots don't share the same document, similar to other TextSnapshotRange methods. If this is a problem, check that the snapshots' documents are the same before calling the method.

Text Buffer Reader Updates

The ITextBufferReader interface has been refined and core portions of it moved into a new interface in the Core library. These updates have been made:

  • Fundamental portions of ITextBufferReader split into a new ISimpleTextBufferReader interface, which ITextBufferReader now inherits. This is not a breaking change other than which interface defines the same members.
  • HasStackEntries property - Renamed to HasStates for better clarity.
  • Push property - Renamed to PushState for better clarity.
  • Pop property - Renamed to PopState for better clarity.
  • PopAll method - Removed since not very useful. If replacement logic is needed, call PopState until HasStates is false.

Several Types Moved to New Core Assembly

This release includes a new Core assembly that is effectively meant to serve as a collection of basics types that are unrelated to any UI framework and can be easily supported across platforms. The following types have been moved to the new Core assembly:

Other Notable Changes

In addition, the following notable changes have also been made in this release.

  • The default value for TextStylePreview.Text was changed from "AaBbCcXxYyZz" to "ij = I::oO(0xB81l);". If the original value is preferred, it can be restored by explicitly setting the Text property to the desired value.
  • In cleaning up APIs, the setters have been removed from the ITextRangeProvider and ITextPositionRangeProvider interfaces. A provider should only return a value, and almost all implementations of that setter threw an unsupported exception.

Additional Breaking Changes

New functionality was added in this release to support a Menu Factory for generating contextual menus. In order to support this functionality, the following breaking changes were necessary:

To facilitate working with native WinForms menu controls, the MenuFactory.WrapMenu method can be used to wrap a ContextMenuStrip in a class that implements the IMenu interface. The WrapMenuItem and WrapMenuSeparator methods are also available for ToolStripMenuItem and ToolStripSeparator, respectively.

Alternatively, any menu customization can be rewritten to use the current menu factory. See the Menu Factory topic for additional details.

Assembly Image and Cursor Resources Moved to Root Path Level

All embedded image and cursor resources within product assemblies have been moved to a root path level. The affected resources are typically only referenced by internal Actipro code and should not affect customer application logic.

Product Metadata Namespace Changes

Metadata for each Actipro product was previously housed within an ActiproSoftware.Products namespace. This has been renamed to the ActiproSoftware.Properties namespace instead. Types in this namespace hierarchy are not typically used outside of Actipro-written code.

Tip

Find ActiproSoftware.Products and replace with ActiproSoftware.Properties to convert any references to affected types.

Generic Collections

Several non-generic collection classes were updated to use generic base types in order to improve type safety and performance. Changes in the base type have resulted in potentially breaking changes, although we expect most users will not be impacted by these changes.

List Collections

The following collections were changed to implement IList<T> (though IList is still explicitly implemented):

For each class above, the following breaking changes were made (where T refers to the Type of object stored in each collection):

  • The Add(T) method no longer returns the index at which the item was added. The parameter for the T object was renamed as item.
  • The Contains(T) method parameter for the T object was renamed as item.
  • The CopyTo(Array, int) method has been replaced by the CopyTo(T[], int) method and is no longer virtual.
  • The Count property is no longer virtual.
  • The GetEnumerator() method is no longer virtual.
  • The IndexOf(T) method parameter for the T object was renamed as item.
  • The Insert(int, T) method parameter for the T object was renamed as item.
  • The Remove(T) method parameter for the T object was renamed as item.
  • The ICollection.IsSynchonized implicit property implementation has been removed.
  • The ICollection.SyncRoot implicit property implementation has been removed.
  • The IList.IsFixedSize implicit property implementation has been removed.
  • The IList.IsReadOnly implicit property implementation has been removed.

Bars Library Collections

Changes in the base type have resulted in potentially breaking changes for the following classes:

For each class above, the following breaking changes were made (where T refers to the Type of object stored in each collection):

  • The Add(T) method no longer returns the index at which the item was added.
  • The Contains(T) method is no longer virtual.
  • The CopyTo(Array, int) method has been replaced by the CopyTo(T[], int) method and is no longer virtual.
  • The Count property is no longer virtual.
  • The GetEnumerator() method is no longer virtual.
  • The IndexOf(T) method is no longer virtual.
  • The InnerList property of type ArrayList has been replaced by the Items property of type IList<T>.
  • The ToArray method was removed (applies to BarManagerDockableToolBarCollection and BarModeCollection only). Use the LINQ extension method instead, which requires importing the System.Linq namespace.
  • The explicitly defined ICollection.IsSynchonized property implementation has been removed and is no longer virtual.
  • The explicitly defined ICollection.SyncRoot property implementation has been removed and is no longer virtual.
  • The explicitly defined IList.IsFixedSize property implementation has been removed and is no longer virtual.
  • The explicitly defined IList.IsReadOnly property implementation has been removed and is no longer virtual.
  • The virtual OnObjectAdded method has been renamed to OnItemAdded.
  • The virtual OnObjectAdding method has been renamed to OnItemAdding.
  • The virtual OnObjectRemoved method has been renamed to OnItemRemoved.
  • The virtual OnObjectRemoving method has been renamed to OnItemRemoving.

Docking Library Collections

The following read-only collections were changed from ReadOnlyCollectionBase to a custom class that derives from ReadOnlyCollection<T>:

For each class above, the following breaking changes were made (where T refers to the Type of object stored in each collection):

  • The ToArray method was removed. Use the LINQ extension method instead, which requires importing the System.Linq namespace.

Bars Library

Breaking Changes

The following list of additional breaking changes were made for this update:

  • BarLayoutXmlSerializer
    • ThrowException method renamed to CreateException and returns an Exception to be thrown by the caller.
    • ThrowUnrecognizedTagException method renamed to CreateUnrecognizedTagException and returns an Exception to be thrown by the caller.
  • KeysCollection base type changed from CollectionBase to Collection<Keys>, which results in the following additional changes:
    • The Add method no longer returns the index at which the item was added.
    • The Contains method is no longer virtual.
    • The IndexOf method is no longer virtual.

Shared Library

Breaking Changes

The following list of breaking changes were made for this update:

  • ILogicalTreeNode.Children property type changed from IList to IList<ILogicalTreeNode>.
  • LogicalTreeNodeBase.CreateChildren virtual method return type changed from IList to IList<ILogicalTreeNode>.
  • LogicalTreeNodeCollection updated to support generics.
    • Implemented interface changed from IList to IList<ILogicalTreeNode>.
    • CopyTo array parameter value type changed from Array to ILogicalTreeNode[].
    • GetEnumerator return type changed from IEnumerator to IEnumerator<ILogicalTreeNode> and is no longer virtual.
    • IsFixedSize property removed. The previous property always returned false.
    • IsSynchronized property removed.
    • SyncRoot property removed.
  • Border.GetInnerBounds overload that did not accept a Sides argument has been removed and the other overload has been updated to default to Sides.All. Method calls are not impacted by this change, but derived classes that had an override for either virtual method will need to be updated to match the new base methods.
  • MarkupLabelElement
    • Children property type changed from IList to IList<ILogicalTreeNode>.
    • Parent property setter access changed from public to internal since it is for internal use only.
  • UIControl updated to support changes in ILogicalTreeNode.
    • CreateChildren return type changed from IList to IList<ILogicalTreeNode>.

Obsolete Form Methods

Starting with .NET 10, the Form.OnClosing and Form.OnClosed methods have been officially marked obsolete in favor of Form.OnFormClosing and Form.OnFormClosed. These methods have been deprecated for a long time, but the warnings are new for .NET 10.

All built-in forms used by our products have moved to Form.OnFormClosing and Form.OnFormClosed.

Any custom classes that derive from our forms and override the obsolete methods should also be moved to OnFormClosing and OnFormClosed to ensure any base functionality is maintained.

This change was applied to all .NET and .NET Framework targets, not just .NET 10.