
{"id":6,"date":"2017-04-04T03:25:04","date_gmt":"2017-04-04T03:25:04","guid":{"rendered":"http:\/\/bakke.online\/?p=6"},"modified":"2017-04-04T03:25:04","modified_gmt":"2017-04-04T03:25:04","slug":"show-environment-bar-in-dynamics-ax-forms","status":"publish","type":"post","link":"https:\/\/www.bakke.online\/index.php\/2017\/04\/04\/show-environment-bar-in-dynamics-ax-forms\/","title":{"rendered":"Show environment bar in Dynamics AX forms"},"content":{"rendered":"<p>When working with multiple Dynamics AX environments, it&#8217;s quite useful to have a visual reminder of which environment you&#8217;re working in.<\/p>\n<p>It is possible to use the instance name in the client configuration to provide this hint, but the instance name is not validated, nor does it indicate to the client which instance to connect to. \u00a0The connection is established only based on the host name, port name and WSDL port. \u00a0It is, in fact, possible to specify anything at all as the instance name:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-7\" src=\"https:\/\/www.bakke.online\/wp-content\/uploads\/2017\/04\/configuration-300x264.png\" alt=\"\" width=\"300\" height=\"264\" \/><\/p>\n<p>My production server does NOT have an instance named MickeyMouse. \u00a0I promise&#8230; \u00a0Really&#8230;<\/p>\n<p><!--more-->Connecting to the AX instance shows this in the status bar:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-9\" src=\"https:\/\/www.bakke.online\/wp-content\/uploads\/2017\/04\/statusbar.png\" alt=\"\" width=\"290\" height=\"42\" \/><\/p>\n<p>This also relies on the user having enabled this information to be shown in the status bar, and even if they have, this will eventually come to bite you when you start copying configurations and configuration files, so a better solution is needed.<\/p>\n<p>The following shows how to add an information bar at the bottom of each form, like this:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-10\" src=\"https:\/\/www.bakke.online\/wp-content\/uploads\/2017\/04\/environmentindicator-300x63.png\" alt=\"\" width=\"300\" height=\"63\" \/><\/p>\n<p>This has been developed and tested on AX2012R3, but it will most likely work unchanged or with only minor changes on other versions of AX2012, possibly even on AX2009 and older, although more substantial changes are likely to be necessary. \u00a0The general concept would remain the same, though.<\/p>\n<p>First we need to add a couple of local members to the SysSetupFormRun class:<\/p>\n<pre><span style=\"color: #008000;\"><em>\/\/ This is a framework class. Customizing this class may cause problems with future upgrades to the software.<\/em><\/span>\n<span style=\"color: #0000ff;\"><strong>public class<\/strong><\/span> SysSetupFormRun <span style=\"color: #0000ff;\"><strong>extends<\/strong> <\/span>FormRun\n{\n SysWorkflowFormControls workflowControls;\n<em><span style=\"color: #008000;\"> \/\/ &lt;GEERU&gt;\n \/\/ Event listeners list\n<\/span><\/em> List listeners_W;\n<em><span style=\"color: #008000;\"> \/\/ &lt;\/GEERU&gt;<\/span><\/em>\n\n <span style=\"color: #008000;\"><em>\/\/ EB 11\/02\/2016: Add environment indicator ==&gt;<\/em><\/span>\n FormGroupControl EB_envBottomGroup;\n FormWindowControl EB_envImage;\n FormStaticTextControl EB_envStatic;\n FormButtonControl EB_envHideButton;\n <span style=\"color: #008000;\"><em>\/\/ EB 11\/02\/2016: Add environment indicator &lt;==<\/em><\/span>\n\n#<span style=\"color: #0000ff;\"><strong>if<\/strong><\/span>.never\n #define.CurrentVersion(<span style=\"color: #ff0000;\"><strong>1<\/strong><\/span>)\n #localmacro.CurrentList\n #endmacro\n#endif\n}<\/pre>\n<p>Next, override the run() method, to make sure that the elements needed for the environment indicator are created every time a form is opened.<\/p>\n<pre><span style=\"color: #008000;\"><em>\/\/ EB 11\/02\/2016: Add environment indicator<\/em><\/span>\n<span style=\"color: #0000ff;\"><strong>public void<\/strong><\/span> run()\n{\n<span style=\"color: #0000ff;\"><strong>  str<\/strong> <\/span>message;\n  <span style=\"color: #0000ff;\"><strong>int<\/strong> <\/span>rgb;\n  <span style=\"color: #0000ff;\"><strong>str<\/strong> <\/span>dbName;\n\n  <span style=\"color: #0000ff;\"><strong>super<\/strong><\/span>();<\/pre>\n<p>The first thing I&#8217;m\u00a0going to do is to call super() to let the system initialise the form, before I start customising it.<\/p>\n<p>Next I&#8217;m checking what type of form this is. \u00a0We don&#8217;t want to show the indicator on embedded forms such as web parts, drop dialogs, etc. \u00a0This code makes sure it only shows on traditional forms and list pages.<\/p>\n<pre><span style=\"color: #0000ff;\"><strong>if<\/strong><\/span>( this.isDetached() &amp;&amp; ( this.design().style() != FormStyle::DropDialog ) )\n {<\/pre>\n<p>In my case, I can determine which environment I&#8217;m running in by checking the database name, as we have a consistent naming convention around here. \u00a0I choose a suitable text and colour based on the database name returned.<\/p>\n<pre>dbName = SysSQLSystemInfo::construct().getloginDatabase();\ndbName = <span style=\"color: #0000ff;\"><strong>subStr<\/strong><\/span>( dbName, <span style=\"color: #0000ff;\"><strong>strFind<\/strong><\/span>( dbName, <span style=\"color: #993300;\">\"_\"<\/span>, <span style=\"color: #ff0000;\"><strong>1<\/strong><\/span>, <span style=\"color: #0000ff;\"><strong>strLen<\/strong><\/span>( dbName ) ) + <span style=\"color: #ff0000;\"><strong>1<\/strong><\/span>, <span style=\"color: #0000ff;\"><strong>strLen<\/strong><\/span>( dbName ) );\n\n<span style=\"color: #0000ff;\"><strong>switch<\/strong><\/span>( dbName )\n{\n  <span style=\"color: #0000ff;\"><strong>case<\/strong> <\/span><span style=\"color: #993300;\">\"Dev\"<\/span>:\n    message = <span style=\"color: #993300;\">\"Development environment - Be prepared for weirdness and random crashes\"<\/span>;\n    rgb = WinAPI::RGB2int( <span style=\"color: #ff0000;\"><strong>160<\/strong><\/span>, <span style=\"color: #ff0000;\"><strong>240<\/strong><\/span>, <span style=\"color: #ff0000;\"><strong>255<\/strong> <\/span>);\n    <span style=\"color: #0000ff;\"><strong>break<\/strong><\/span>;\n<span style=\"color: #0000ff;\"><strong>  case<\/strong> <\/span><span style=\"color: #993300;\">\"Test\"<\/span>:\n    message = <span style=\"color: #993300;\">\"Test environment\"<\/span>;\n    rgb = WinAPI::RGB2int( <span style=\"color: #ff0000;\"><strong>160<\/strong><\/span>, <span style=\"color: #ff0000;\"><strong>255<\/strong><\/span>, <span style=\"color: #ff0000;\"><strong>160<\/strong> <\/span>);\n    <span style=\"color: #0000ff;\"><strong>break<\/strong><\/span>;\n  <span style=\"color: #0000ff;\"><strong>case<\/strong> <\/span><span style=\"color: #993300;\">\"Staging\"<\/span>:\n    message = <span style=\"color: #993300;\">\"Staging environment\"<\/span>;\n    rgb = WinAPI::RGB2int( <span style=\"color: #ff0000;\"><strong>255<\/strong><\/span>, <span style=\"color: #ff0000;\"><strong>255<\/strong><\/span>, <span style=\"color: #ff0000;\"><strong>0<\/strong><\/span> );\n    <span style=\"color: #0000ff;\"><strong>break<\/strong><\/span>;\n <span style=\"color: #0000ff;\"><strong>case<\/strong> <\/span><span style=\"color: #993300;\">\"Live\"<\/span>:\n   <span style=\"color: #0000ff;\"><strong>return<\/strong><\/span>;\n }<\/pre>\n<p>Next I&#8217;m going to add the controls to the form through X++ code.<\/p>\n<pre>EB_envBottomGroup = this.design().addControl( FormControlType::Group, <span style=\"color: #993300;\">\"EB_envBottomGroup\"<\/span> );\nEB_envImage = EB_envBottomGroup.addControl( FormControlType::Image, <span style=\"color: #993300;\">\"EB_envImage\"<\/span> );\nEB_envStatic = EB_envBottomGroup.addControl( FormControlType::StaticText, <span style=\"color: #993300;\">\"EB_envStatic\"<\/span> );\nEB_envHideButton = EB_envBottomGroup.addControl( FormControlType::Button, <span style=\"color: #993300;\">\"EB_envHideButton\"<\/span> );<\/pre>\n<p>EB_envBottomGroup is a group control that will contain the other controls. \u00a0I size and style it before moving on to the other controls.<\/p>\n<pre>EB_envBottomGroup.widthMode( FormWidth::ColumnWidth );\nEB_envBottomGroup.heightMode( FormHeight::Auto );\nEB_envBottomGroup.colorScheme( FormColorScheme::RGB );\nEB_envBottomGroup.backStyle( FormBackStyle::Opaque );\nEB_envBottomGroup.backgroundColor( rgb );\nEB_envBottomGroup.frameType( FormFrameType::None );\nEB_envBottomGroup.topMargin( <span style=\"color: #ff0000;\"><strong>5<\/strong><\/span> );\nEB_envBottomGroup.bottomMargin( <span style=\"color: #ff0000;\"><strong>0<\/strong><\/span> );\nEB_envBottomGroup.leftMargin( <span style=\"color: #ff0000;\"><strong>5<\/strong><\/span> );\nEB_envBottomGroup.rightMargin( <span style=\"color: #ff0000;\"><strong>5<\/strong><\/span> );<\/pre>\n<p>EB_envImage is just an icon, used to make the indicator bar a bit more interesting. \u00a0Completely optional, of course. \u00a0I am using resource ID 918 here, but if you want a different one, have a look through the embedded resources by using the tutorial_Resources form.<\/p>\n<pre>EB_envImage.width( <span style=\"color: #ff0000;\"><strong>15<\/strong><\/span>, FormWidth::Auto );\nEB_envImage.height( <span style=\"color: #ff0000;\"><strong>15<\/strong><\/span>, FormHeight::Auto );\nEB_envImage.leftMode( FormLeft::LeftEdge );\nEB_envImage.imageResource( <span style=\"color: #ff0000;\"><strong>918<\/strong> <\/span>);\nEB_envImage.imagemode( <span style=\"color: #ff0000;\"><strong>1<\/strong><\/span> );\nEB_envImage.backStyle( FormBackStyle::Transparent );\nEB_envImage.showLabel( <span style=\"color: #0000ff;\"><strong>false<\/strong> <\/span>);<\/pre>\n<p>Next, EB_envStatic is a static text control where I display the environment indicator text.<\/p>\n<pre>EB_envStatic.alignment( FormAlignment::Center );\nEB_envStatic.fontSize( <span style=\"color: #ff0000;\"><strong>10<\/strong> <\/span>);\nEB_envStatic.text( message );<\/pre>\n<p>The final control is a button which can be used to hide the environment indicator. \u00a0Perhaps it is taking up too much space, or it needs to be hidden in order to do a screen shot. \u00a0For whatever reason, it is good practice to allow the user to hide it when necessary. \u00a0I&#8217;m using resource ID 8008 here, which is a small &#8220;Close&#8221; icon. \u00a0Use whatever other icon you want, but be mindful of the size of the environment bar. \u00a0It should not be too large, or it will take up too much space, and some icons don&#8217;t scale that well to small sizes.<\/p>\n<pre>EB_envHideButton.width( <span style=\"color: #ff0000;\"><strong>15<\/strong><\/span>, FormWidth::Auto );\nEB_envHideButton.height( <span style=\"color: #ff0000;\"><strong>15<\/strong><\/span>, FormHeight::Auto );\nEB_envHideButton.leftMode( FormLeft::RightEdge );\nEB_envHideButton.normalResource( <span style=\"color: #ff0000;\"><strong>8008<\/strong> <\/span>);\nEB_envHideButton.buttonDisplay( FormButtonDisplay::ImageOnly );\nEB_envHideButton.backStyle( FormBackStyle::Transparent );\nEB_envHideButton.style( ButtonStyle::Link );<\/pre>\n<p>Finally, we have to register an override method so we can capture the click event and actually hide the environment indicator.<\/p>\n<pre>    EB_envHideButton.registerOverrideMethod( <span style=\"color: #0000ff;\"><strong>methodStr<\/strong><\/span>( FormButtonControl, clicked ), <span style=\"color: #0000ff;\"><strong>methodStr<\/strong><\/span>( SysSetupFormRun, EB_hideEnvButton_Clicked ), this );\n  }\n}<\/pre>\n<p>That&#8217;s it for the run method. \u00a0Now add a new method to the SysSetupFormRun class and call it EB_hideEnvButtonClicked. \u00a0(Of course, the actual prefix is totally up to you and the naming conventions you follow.)<\/p>\n<pre><em><span style=\"color: #008000;\">\/\/ EB 11\/02\/2016: Add environment indicator<\/span><\/em>\n<span style=\"color: #0000ff;\"><strong>public void<\/strong><\/span> EB_hideEnvButton_Clicked( FormWindowControl _caller )\n{\n  EB_envBottomGroup.visible( <span style=\"color: #0000ff;\"><strong>false<\/strong> <\/span>);\n}<\/pre>\n<p>That&#8217;s it. \u00a0Recompile the class and update the CIL code. \u00a0Users will then get the environment indicator at the bottom of their forms.<\/p>\n<p>Please, make sure you do this in a dev\/test environment first, and test it before loading to production.<\/p>\n<p>An XPO containing this modification is available here:\u00a0<a href=\"https:\/\/www.bakke.online\/wp-content\/uploads\/2017\/04\/Class_SysSetupFormRun.zip\">Class_SysSetupFormRun.zip<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>When working with multiple Dynamics AX environments, it&#8217;s quite useful to have a visual reminder of which environment you&#8217;re working in. It is possible to use the instance name in the client configuration to provide this hint, but the instance name is not validated, nor does it indicate to the client which instance to connect &hellip; <a href=\"https:\/\/www.bakke.online\/index.php\/2017\/04\/04\/show-environment-bar-in-dynamics-ax-forms\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Show environment bar in Dynamics AX forms&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,1],"tags":[2,3,5],"class_list":["post-6","post","type-post","status-publish","format-standard","hentry","category-dynamics-ax","category-uncategorized","tag-ax2012r3","tag-dynamics-ax","tag-user-interface"],"_links":{"self":[{"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/posts\/6","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/comments?post=6"}],"version-history":[{"count":0,"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/posts\/6\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/media?parent=6"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/categories?post=6"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/tags?post=6"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}