{"id":1424,"date":"2026-04-29T18:52:06","date_gmt":"2026-04-29T18:52:06","guid":{"rendered":"https:\/\/cloudclif.com\/blogs\/?p=1424"},"modified":"2026-04-30T05:29:12","modified_gmt":"2026-04-30T05:29:12","slug":"form-extensions-in-d365-fo-data-sources-controls-and-the-gotchas-nobody-warns-you-about","status":"publish","type":"post","link":"https:\/\/cloudclif.com\/blogs\/2026\/04\/29\/form-extensions-in-d365-fo-data-sources-controls-and-the-gotchas-nobody-warns-you-about\/","title":{"rendered":"Form Extensions in D365 F&amp;O: Data Sources, Controls, and the Gotchas Nobody Warns You About\u00a0"},"content":{"rendered":"\n<p><em>Reading time: ~9 minutes.<\/em>&nbsp;<\/p>\n\n\n\n<p>Form extensions are where most F&amp;O developers stop reading the Microsoft Learn docs too early. The syntax looks straightforward \u2014 slap [ExtensionOf] on a class, name your extension method the same as the base, call next, done. Then you spend an afternoon wondering why your data source extension compiles but never fires, or why your control extension can wrap&nbsp;clicked() but not&nbsp;lookup(), or why element. resolves at compile time but blows up at runtime. This post is the part of the docs they&nbsp;don&#8217;t&nbsp;make you read.&nbsp;<\/p>\n\n\n\n<p>If you&nbsp;haven&#8217;t&nbsp;read the earlier posts on the underlying CoC mechanics:&nbsp;<a href=\"https:\/\/cloudclif.com\/blogs\/2026\/04\/26\/chain-of-command-in-d365-fo-a-practitioners-guide-to-when-and-when-not-to-use-it\/\" data-type=\"post\" data-id=\"1398\">Chain of Command in D365 F&amp;O<\/a>. The decision framework on CoC vs event handlers is here:&nbsp;<a href=\"https:\/\/cloudclif.com\/blogs\/2026\/04\/27\/event-handlers-vs-chain-of-command-the-real-decision-framework-for-2026\/\" data-type=\"post\" data-id=\"1409\">Event Handlers vs Chain of Command<\/a>.&nbsp;<\/p>\n\n\n\n<p><strong>Three extension targets, three separate extension classes<\/strong>&nbsp;<\/p>\n\n\n\n<p>First rule, easy to violate: a single extension class can target exactly one&nbsp;form&nbsp;artifact. Form, data source, data field, or control \u2014 each one is its own [ExtensionOf]. You cannot combine them. Trying to wrap a form-level method and a data source method in the same class either&nbsp;fails to&nbsp;compile or \u2014 worse \u2014 silently ignores the wrong one.&nbsp;<\/p>\n\n\n\n<p>The four extension target shapes&nbsp;you&#8217;ll&nbsp;write:&nbsp;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>[ExtensionOf(formStr(MyForm))]&nbsp;\u2014 wraps form-level methods like&nbsp;init,&nbsp;run,&nbsp;close.&nbsp;<\/li>\n\n\n\n<li>[ExtensionOf(formDataSourceStr(MyForm,&nbsp;MyDS))]&nbsp;\u2014 wraps data source methods like&nbsp;init,&nbsp;active,&nbsp;executeQuery,&nbsp;validateWrite,&nbsp;write.&nbsp;<\/li>\n\n\n\n<li>[ExtensionOf(formDataFieldStr(MyForm,&nbsp;MyDS,&nbsp;MyField))]&nbsp;\u2014 wraps the methods on a specific data field, primarily&nbsp;validate,&nbsp;modified,&nbsp;lookup.&nbsp;<\/li>\n\n\n\n<li>[ExtensionOf(formControlStr(MyForm,&nbsp;MyControl))]&nbsp;\u2014&nbsp;wraps&nbsp;control methods like&nbsp;clicked,&nbsp;modified,&nbsp;validate.&nbsp;<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><img fetchpriority=\"high\" decoding=\"async\" width=\"1024\" height=\"1024\" src=\"https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/0cd42837-e908-438a-9466-5b464dfe0392-1-1024x1024.png\" alt=\"\" class=\"wp-image-1432\" srcset=\"https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/0cd42837-e908-438a-9466-5b464dfe0392-1-1024x1024.png 1024w, https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/0cd42837-e908-438a-9466-5b464dfe0392-1-300x300.png 300w, https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/0cd42837-e908-438a-9466-5b464dfe0392-1-150x150.png 150w, https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/0cd42837-e908-438a-9466-5b464dfe0392-1-768x768.png 768w, https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/0cd42837-e908-438a-9466-5b464dfe0392-1-1170x1170.png 1170w, https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/0cd42837-e908-438a-9466-5b464dfe0392-1-585x585.png 585w, https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/0cd42837-e908-438a-9466-5b464dfe0392-1.png 1254w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Microsoft&#8217;s method-wrapping reference shows the pattern explicitly. Worth quoting because the next bit catches people:&nbsp;<\/p>\n\n\n\n<p>Microsoft&#8217;s method-wrapping reference shows the pattern explicitly. Worth quoting because the next bit catches people:&nbsp;<\/p>\n\n\n\n<p><em>&#8220;Like other CoC methods, these methods must always call next to invoke the next method in the chain, so that the chain can go all the way to the kernel or native implementation in the runtime behavior. The call to next is equivalent to a call to&nbsp;super() from the form itself to help guarantee that the base behavior in the runtime always runs as expected.&#8221;<\/em>&nbsp;<\/p>\n\n\n\n<p>Translation: the next call inside a form-nested CoC&nbsp;isn&#8217;t&nbsp;optional. Skipping it on a data source&nbsp;init&nbsp;won&#8217;t&nbsp;just break your extension \u2014 it can break the form&#8217;s data binding entirely. The same rules from class-level CoC apply. The framework just gives you more places to forget them.&nbsp;<\/p>\n\n\n\n<p><strong>Form data source extensions \u2014 the methods that&nbsp;actually exist<\/strong>&nbsp;<\/p>\n\n\n\n<p>Data source methods correspond to the lifecycle of a record in a&nbsp;form&#8217;s&nbsp;grid or detail layout. The&nbsp;most commonly wrapped&nbsp;ones, with what each is&nbsp;actually good&nbsp;for:&nbsp;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>init()&nbsp;\u2014 fires&nbsp;once when&nbsp;the form initializes.&nbsp;Use for&nbsp;data-source-level setup that needs to happen before any record is fetched.&nbsp;<\/li>\n\n\n\n<li>active()&nbsp;\u2014 fires when the user navigates to a different record. This is the workhorse method for enabling\/disabling controls based on the currently selected&nbsp;record&#8217;s&nbsp;state.&nbsp;<\/li>\n\n\n\n<li>executeQuery()&nbsp;\u2014 fires when the data source query runs. Use to inject filters or&nbsp;modify&nbsp;the query before records are fetched.&nbsp;<\/li>\n\n\n\n<li>validateWrite()&nbsp;\u2014 fires before a record&nbsp;is&nbsp;saved. Use to add custom save-time validation on top of the table-level rules.&nbsp;<\/li>\n\n\n\n<li>write()&nbsp;\u2014 fires when the record is saved. Use for post-save side effects that need to know the&nbsp;form&nbsp;context.&nbsp;<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"1024\" height=\"1024\" src=\"https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/2c8ff9f8-ed2f-4de0-be9e-471a18d05705-1024x1024.png\" alt=\"\" class=\"wp-image-1433\" srcset=\"https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/2c8ff9f8-ed2f-4de0-be9e-471a18d05705-1024x1024.png 1024w, https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/2c8ff9f8-ed2f-4de0-be9e-471a18d05705-300x300.png 300w, https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/2c8ff9f8-ed2f-4de0-be9e-471a18d05705-150x150.png 150w, https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/2c8ff9f8-ed2f-4de0-be9e-471a18d05705-768x768.png 768w, https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/2c8ff9f8-ed2f-4de0-be9e-471a18d05705-1170x1170.png 1170w, https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/2c8ff9f8-ed2f-4de0-be9e-471a18d05705-585x585.png 585w, https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/2c8ff9f8-ed2f-4de0-be9e-471a18d05705.png 1254w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>A typical&nbsp;active()&nbsp;extension that enables or disables a control based on the current record. The pattern below is from Hafsa Fareed Siddiqui&#8217;s writeup on form data source extensions, which is the cleanest community example of the&nbsp;element.&nbsp;trick (more on that in a moment):&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;ExtensionOf(formDataSourceStr(SalesTable, SalesTable))] \nfinal class SalesTable_Ds_MyExt_Extension \n{ \n    public int active() \n    { \n        int ret = next active(); \n\n        SalesTable salesTable = this.cursor(); \n\n        if (salesTable.RecId) \n        { \n            element.control( \n                element.controlId(formControlStr(SalesTable, OfferNumber)) \n            ).enabled(salesTable.MyCustomFlag); \n        } \n\n        return ret; \n    } \n\n} <\/code><\/pre>\n\n\n\n<p><strong>The element. trick \u2014 what it is, when it works, when it&nbsp;doesn&#8217;t<\/strong>&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"1024\" height=\"1024\" src=\"https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/7098fdb9-4557-4079-bc3c-2f2beee9d2a8-1024x1024.png\" alt=\"\" class=\"wp-image-1434\" srcset=\"https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/7098fdb9-4557-4079-bc3c-2f2beee9d2a8-1024x1024.png 1024w, https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/7098fdb9-4557-4079-bc3c-2f2beee9d2a8-300x300.png 300w, https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/7098fdb9-4557-4079-bc3c-2f2beee9d2a8-150x150.png 150w, https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/7098fdb9-4557-4079-bc3c-2f2beee9d2a8-768x768.png 768w, https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/7098fdb9-4557-4079-bc3c-2f2beee9d2a8-1170x1170.png 1170w, https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/7098fdb9-4557-4079-bc3c-2f2beee9d2a8-585x585.png 585w, https:\/\/cloudclif.com\/blogs\/wp-content\/uploads\/2026\/04\/7098fdb9-4557-4079-bc3c-2f2beee9d2a8.png 1254w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>From inside a form-nested extension class,&nbsp;element&nbsp;is a reference to the form itself \u2014 the equivalent of&nbsp;this&nbsp;from inside the form&#8217;s own code. Microsoft&#8217;s method-wrapping page documents this directly:&nbsp;<\/p>\n\n\n\n<p><em>&#8220;\/\/use&nbsp;element.FormToExtendVariable&nbsp;to access form&#8217;s variables and&nbsp;datasources&nbsp;\/&nbsp;element.FormToExtendMethod() to call form methods&#8221;<\/em>&nbsp;<\/p>\n\n\n\n<p>Powerful.&nbsp;Also&nbsp;a footgun. Three things to know:&nbsp;<\/p>\n\n\n\n<p><strong>1. element resolves to the form-level scope, not the data source scope.&nbsp;<\/strong>If you write&nbsp;element.someMethod()&nbsp;inside a data source extension,&nbsp;you&#8217;re&nbsp;calling a form method, not a data source method. This is usually what you want \u2014 but be intentional.&nbsp;<\/p>\n\n\n\n<p><strong>2. Compilation does not guarantee runtime existence.&nbsp;<\/strong>element.SomeVariable&nbsp;compiles if the form declares&nbsp;SomeVariable&nbsp;at the form level today. If a service update removes or renames it, your code still&nbsp;compiles against&nbsp;the new metadata only if the variable still exists with the same name. Microsoft does not guarantee form-internal variables are stable across versions. Treat&nbsp;element.&nbsp;access to form-internal state as a low-trust dependency, the same as&nbsp;you&#8217;d&nbsp;treat&nbsp;_args.getArg(&#8220;_someParam&#8221;)&nbsp;in a Pre\/Post handler.&nbsp;<\/p>\n\n\n\n<p><strong>3. From a data field extension, the path to the form is longer.&nbsp;<\/strong>Data field extensions&nbsp;don&#8217;t&nbsp;get&nbsp;element&nbsp;directly. The documented pattern (covered in d365ffo.com&#8217;s data source\/control walkthroughs) is to cast&nbsp;this&nbsp;to a&nbsp;FormDataObject, get the data source, then get the form run from the data source.&nbsp;It&#8217;s&nbsp;verbose but it works.&nbsp;<\/p>\n\n\n\n<p><strong>Form control extensions \u2014 and the&nbsp;OnClicked&nbsp;vs&nbsp;clicked() decision<\/strong>&nbsp;<\/p>\n\n\n\n<p>Control extensions wrap methods on a specific named control. The two&nbsp;flavours&nbsp;of extension here cause genuine confusion:&nbsp;<\/p>\n\n\n\n<p><strong>CoC on the control&nbsp;method itself&nbsp;\u2014&nbsp;<\/strong>wrap&nbsp;clicked(),&nbsp;modified(),&nbsp;lookup(), or&nbsp;validate()&nbsp;using&nbsp;[ExtensionOf(formControlStr(&#8230;))].&nbsp;You&#8217;re&nbsp;overriding the X++ method that exists on the control.&nbsp;<\/p>\n\n\n\n<p><strong>Event handlers on framework&nbsp;events \u2014&nbsp;<\/strong>[FormControlEventHandler]&nbsp;subscribing to events like&nbsp;OnClicked,&nbsp;OnModified,&nbsp;OnValidating.&nbsp;You&#8217;re&nbsp;reacting to a framework event, not overriding a method.&nbsp;<\/p>\n\n\n\n<p>On most controls, both options exist for the same logical thing.&nbsp;So&nbsp;which one?&nbsp;<\/p>\n\n\n\n<p>Use CoC when you need to influence the control&#8217;s own&nbsp;behaviour&nbsp;\u2014 change the return value of&nbsp;validate(),&nbsp;suppress&nbsp;or alter what&nbsp;clicked() does,&nbsp;modify&nbsp;what&nbsp;lookup() shows. Use event handlers when you only need to react \u2014 log something, push a notification, refresh another control. Microsoft Learn&#8217;s CoC reference shows both,&nbsp;in&nbsp;the same page, as legitimate choices for the same ostensible task. The decision is functionally identical to the class-method CoC vs Pre\/Post decision from Day 2: CoC for influence, handlers for reaction.&nbsp;<\/p>\n\n\n\n<p><strong>The gotchas that bite in production<\/strong>&nbsp;<\/p>\n\n\n\n<p>Five form-extension surprises that appear on real projects.&nbsp;<\/p>\n\n\n\n<p><strong>1. Static methods&nbsp;can&#8217;t&nbsp;be wrapped&nbsp;on&nbsp;form classes.&nbsp;<\/strong>Microsoft Learn states this explicitly:&nbsp;<em>&#8220;The ability to wrap static methods doesn&#8217;t apply to forms.&nbsp;In X++, a form class isn&#8217;t a new class, and you can&#8217;t instantiate or reference it as a normal class.&#8221;<\/em>&nbsp;If&nbsp;you&#8217;ve&nbsp;read this for the first time,&nbsp;that&#8217;s&nbsp;why your&nbsp;form&nbsp;CoC compiled but&nbsp;didn&#8217;t&nbsp;fire.&nbsp;<\/p>\n\n\n\n<p><strong>2. You&nbsp;can&#8217;t&nbsp;add CoC to a method that&nbsp;doesn&#8217;t&nbsp;exist on the base.&nbsp;<\/strong>Same&nbsp;Microsoft page:&nbsp;<em>&#8220;You can&#8217;t add CoC to wrap methods that aren&#8217;t defined in the original base behavior of the nested control type.&#8221;<\/em>&nbsp;You cannot wrap a method on an extension. You cannot invent a new method on a control via CoC. The wrap targets must exist on the base.&nbsp;<\/p>\n\n\n\n<p><strong>3. Form-nested CoC needs separate classes per nested concept.&nbsp;<\/strong>From Day 1, but worth restating because&nbsp;it&#8217;s&nbsp;the most common compile-time-passes-runtime-fails scenario in&nbsp;form&nbsp;work. A data source extension and a control extension on the same form must be in two distinct classes with two distinct&nbsp;[ExtensionOf]&nbsp;attributes.&nbsp;<\/p>\n\n\n\n<p><strong>4. Visual Studio&nbsp;doesn&#8217;t&nbsp;surface&nbsp;wrappable&nbsp;methods.&nbsp;<\/strong>Microsoft&#8217;s own warning:&nbsp;<em>&#8220;Currently, the X++ editor in Microsoft Visual Studio doesn&#8217;t support discovery of methods that you can wrap. Therefore, you must refer to the system documentation for each nested concept to identify the correct method to wrap and its exact&nbsp;signature.&#8221;<\/em>&nbsp;\u26a0 This is a real productivity tax. Keep the Microsoft Learn method-wrapping page open in a browser tab while&nbsp;you&#8217;re&nbsp;writing form extensions.&nbsp;<\/p>\n\n\n\n<p><strong>5. Default parameter values must come from the base method.&nbsp;<\/strong>If you redeclare a default value in your extension&nbsp;method&nbsp;signature, the compiler rejects it. The default lives on the base; your extension just declares the parameter without one.&nbsp;<\/p>\n\n\n\n<p><strong>3 tricky interview questions (with verified answers)<\/strong>&nbsp;<\/p>\n\n\n\n<p>Each answer traces to a named source linked in the references.&nbsp;<\/p>\n\n\n\n<p><strong>Q1. You need a control to be enabled or disabled based on the currently selected record. Which extension method do you&nbsp;wrap?<\/strong>&nbsp;<\/p>\n\n\n\n<p>The data source&#8217;s&nbsp;active()&nbsp;method.&nbsp;active()&nbsp;fires every time the user navigates to a different record in the data source&#8217;s grid or detail. Wrapping it lets you read&nbsp;this.cursor()&nbsp;for the current record and conditionally enable\/disable form controls via&nbsp;element.control(&#8230;). Wrapping a control&#8217;s own method (like&nbsp;clicked())&nbsp;wouldn&#8217;t&nbsp;help \u2014 those methods only fire when the user interacts with the control, not when the underlying record changes. \u26a0 Note that&nbsp;active()&nbsp;also fires once at form initialization with the first record, so guard against null\/empty cursors if your form can open with no records.&nbsp;<\/p>\n\n\n\n<p><strong>Q2. Why doesn&#8217;t a CoC on a static method of a form class compile, even though the syntax looks correct?<\/strong>&nbsp;<\/p>\n\n\n\n<p>Because forms&nbsp;aren&#8217;t&nbsp;real&nbsp;classes from CoC&#8217;s perspective. Microsoft Learn states the rule directly:&nbsp;<em>&#8220;The ability to wrap static methods doesn&#8217;t apply to forms.&nbsp;In X++, a form class isn&#8217;t a new class, and you can&#8217;t instantiate or reference it as a normal class.&#8221;<\/em>&nbsp;You can wrap instance-level methods on data sources, data fields, and controls \u2014 those are nested concepts the runtime treats as&nbsp;wrappable. Static methods declared at form level are not. The fix is either to refactor the static method into a regular class that you can extend, or to use an event handler if a suitable&nbsp;framework&nbsp;event exists.&nbsp;<\/p>\n\n\n\n<p><strong>Q3. From inside a data field extension, how do you reach a different data source on the same form?<\/strong>&nbsp;<\/p>\n\n\n\n<p>Data field extensions&nbsp;don&#8217;t&nbsp;get&nbsp;element&nbsp;for free. The documented pattern (covered in d365ffo.com&#8217;s writeup on form-level access from extensions) is to cast&nbsp;this&nbsp;to&nbsp;FormDataObject, retrieve the data source from there, get the&nbsp;FormRun&nbsp;from the data source, and then access the other data source through the&nbsp;FormRun. The chain looks like:&nbsp;FormDataObject&nbsp;\u2192&nbsp;datasource() \u2192&nbsp;formRun() \u2192&nbsp;dataSource(formDataSourceStr(&#8230;)) \u2192&nbsp;cursor(). Verbose, but&nbsp;it&#8217;s&nbsp;the supported route. Trying to access form-level state directly from a data field extension is the wrong shape \u2014 the field&nbsp;doesn&#8217;t&nbsp;have first-class access to the form.&nbsp;<\/p>\n\n\n\n<p><strong>What to&nbsp;actually do<\/strong>&nbsp;<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li>Pick one extension target per class. Form, data source, data field, control \u2014 never&nbsp;combine.&nbsp;The compiler will let you write something that looks combined; it won&#8217;t run the way you expect.&nbsp;<\/li>\n<\/ol>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li>Default to data source&nbsp;active() for record-driven enable\/disable logic. Default to control event handlers for pure react-to-click logic. Default to control CoC when you need to influence what the click does.&nbsp;<\/li>\n<\/ol>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li>Treat element. access to form-internal variables as a low-trust dependency.&nbsp;It&#8217;s&nbsp;fine to use, but flag it in code&nbsp;review&nbsp;the same way&nbsp;you&#8217;d&nbsp;flag any reach into another package&#8217;s internals.&nbsp;<\/li>\n<\/ol>\n\n\n\n<ol start=\"4\" class=\"wp-block-list\">\n<li>Keep the Microsoft Learn method-wrapping page open while writing. Visual Studio&nbsp;won&#8217;t&nbsp;tell you what&#8217;s&nbsp;wrappable; the docs will.&nbsp;<\/li>\n<\/ol>\n\n\n\n<ol start=\"5\" class=\"wp-block-list\">\n<li>If a CoC compiles but&nbsp;doesn&#8217;t&nbsp;fire at runtime,&nbsp;check&nbsp;three things in order: is the method&nbsp;actually defined&nbsp;on the base (not on another extension)? Is the method static (in which case it&nbsp;can&#8217;t&nbsp;be wrapped&nbsp;on&nbsp;a form)? Are you sure the extension class is in a package that references the base&nbsp;form&#8217;s&nbsp;package?&nbsp;<\/li>\n<\/ol>\n\n\n\n<p><strong>References<\/strong>&nbsp;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Microsoft Learn<\/strong>&nbsp;\u2014 Class extension: Method wrapping and Chain of Command (learn.microsoft.com\/en-us\/dynamics365\/fin-ops-core\/dev-itpro\/extensibility\/method-wrapping-coc). Authoritative reference. The form-nested section explicitly covers form, data source, data field, and control extension patterns and the static-method-on-forms restriction. Last updated March 2026.&nbsp;<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Microsoft Learn<\/strong>&nbsp;\u2014 Add data sources to forms through extension (learn.microsoft.com\/en-us\/dynamics365\/fin-ops-core\/dev-itpro\/extensibility\/add-datasource). Companion reference for adding new data sources via extension, separate from the method-wrapping concern. Last updated March 2026.&nbsp;<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Hafsa Fareed Siddiqui<\/strong>&nbsp;\u2014 Get records on Form&nbsp;DataSource&nbsp;X++ D365FO (Medium, March 2024). Source for the&nbsp;active() pattern using&nbsp;element.control(&#8230;) shown above. Clean, current example.&nbsp;<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>d365ffo.com<\/strong>&nbsp;\u2014 AX \/ D365FO \u2013 Get&nbsp;datasource&nbsp;from a Form extension class. Source for the&nbsp;FormDataObject&nbsp;\u2192&nbsp;formRun() chain referenced in Q3. Covers form data source, control, and data field extension access patterns.&nbsp;<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Dynamics 365 Musings<\/strong>&nbsp;\u2014 Chain&nbsp;Of&nbsp;Command&nbsp;For&nbsp;Form&nbsp;DataSource&nbsp;(dynamics365musings.com\/chain-of-command-for-form-datasource\/). Practical CoC patterns for&nbsp;form&nbsp;data sources with current syntax. Updated 2024.&nbsp;<\/li>\n<\/ul>\n\n\n\n<p><em>Next up in this series: <\/em><a href=\"https:\/\/cloudclif.com\/blogs\/2026\/04\/30\/table-extensions-vs-coc-on-tables-picking-the-right-tool-for-adding-fields-and-logic\/\" data-type=\"post\" data-id=\"1437\">Table Extensions vs CoC on Tables \u2014 Picking the Right Tool for Adding Fields and Logic <\/a><em>.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Reading time: ~9 minutes.&nbsp; Form extensions are where most F&amp;O developers stop reading the Microsoft Learn docs too early. The syntax looks straightforward \u2014 slap [ExtensionOf] on a class, name&hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_lmt_disableupdate":"","_lmt_disable":"","footnotes":""},"categories":[35],"tags":[],"class_list":["post-1424","post","type-post","status-publish","format-standard","hentry","category-d365-fo"],"_links":{"self":[{"href":"https:\/\/cloudclif.com\/blogs\/wp-json\/wp\/v2\/posts\/1424","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudclif.com\/blogs\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudclif.com\/blogs\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudclif.com\/blogs\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudclif.com\/blogs\/wp-json\/wp\/v2\/comments?post=1424"}],"version-history":[{"count":7,"href":"https:\/\/cloudclif.com\/blogs\/wp-json\/wp\/v2\/posts\/1424\/revisions"}],"predecessor-version":[{"id":1449,"href":"https:\/\/cloudclif.com\/blogs\/wp-json\/wp\/v2\/posts\/1424\/revisions\/1449"}],"wp:attachment":[{"href":"https:\/\/cloudclif.com\/blogs\/wp-json\/wp\/v2\/media?parent=1424"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudclif.com\/blogs\/wp-json\/wp\/v2\/categories?post=1424"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudclif.com\/blogs\/wp-json\/wp\/v2\/tags?post=1424"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}