tag:blogger.com,1999:blog-35467954445881799262024-03-18T08:40:25.390-07:00Alex on DAX (Alex Kwitny)This technical blog will be about my adventures with Microsoft Dynamics 365 for Operations (AX7/D3fo), AX 2012, and AX 2009.Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.comBlogger82125tag:blogger.com,1999:blog-3546795444588179926.post-79862994668305977392019-05-09T10:26:00.000-07:002019-05-09T10:26:09.947-07:00Print statement in D365 and other interesting bitsWe all know the "print" statement, but what I find interesting is in Dynamics 365 for Finance and Operations, Enterprise Edition, it has been changed.<br />
<br />
It works the same, but it now uses System.Diagnostics.Debug::WriteLine("Hello World") to print to the output window.<br />
<br />
You can read more about it and other interesting debugger features here:<br />
<br />
<a href="https://docs.microsoft.com/en-us/dynamics365/unified-operations/dev-itpro/dev-tools/new-x-debugger-features">https://docs.microsoft.com/en-us/dynamics365/unified-operations/dev-itpro/dev-tools/new-x-debugger-features</a>Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.com17tag:blogger.com,1999:blog-3546795444588179926.post-25562860440615602892018-10-23T10:03:00.000-07:002018-10-23T10:03:03.355-07:00Fun and better method to get Args.Caller() nameIn any AX/D365 environment, there's often a need to get the Args.Caller().Name(), except not all possible caller's will have a .name() method, so here's a little function that can be added to a form to get the caller's name in a more proper method.<br />
<br />
<br />
<div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%"><span style="color: #008800; font-weight: bold">private</span> IdentifierName <span style="color: #0066BB; font-weight: bold">getCallerName</span>()
{
Object caller;
SysDictClass sysDictClass;
IdentifierName callerName;
<span style="color: #888888">// There must be a caller to retrieve a name</span>
<span style="color: #008800; font-weight: bold">if</span> (!(element.args() && element.args().caller()))
<span style="color: #008800; font-weight: bold">return</span> callerName;
caller = element.args().caller();
sysDictClass = <span style="color: #008800; font-weight: bold">new</span> SysDictClass(classIdGet(caller));
<span style="color: #888888">// Use reflection & recursion to get the name if possible</span>
<span style="color: #008800; font-weight: bold">while</span> (sysDictClass)
{
<span style="color: #008800; font-weight: bold">if</span> (sysDictClass.hasObjectMethod(identifierStr(Name)))
{
callerName = caller.name();
sysDictClass = <span style="color: #008800; font-weight: bold">null</span>;
}
<span style="color: #008800; font-weight: bold">else</span> <span style="color: #0066BB; font-weight: bold">if</span> (sysDictClass.extend())
{
sysDictClass = <span style="color: #008800; font-weight: bold">new</span> sysDictClass(sysDictClass.extend());
}
<span style="color: #008800; font-weight: bold">else</span>
{
sysDictClass = <span style="color: #008800; font-weight: bold">null</span>;
}
}
<span style="color: #008800; font-weight: bold">return</span> callerName;
}
</pre></div>
Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.com5tag:blogger.com,1999:blog-3546795444588179926.post-85850188048366632802018-04-24T07:40:00.002-07:002018-04-24T08:43:04.237-07:00How to convert a decimal to a fraction in X++ with Dynamics AX or Dynamics 365 FOI had a customer who needed to convert a decimal to fraction, so I just translated this <a href="https://stackoverflow.com/questions/5124743/algorithm-for-simplifying-decimal-to-fractions/32903747#32903747" target="_blank">StackOverflow post</a> where all credit is due. I'm sure someone else will find it useful at some point.<br />
<br />
The two main things in the job below (details taken from StackOverflow) are "_real", which is the value you want to convert, and "_accuracy", which specifies the max relative error; not the max absolute error.<br />
<br />
So _accuracy = 0.01 would find a fraction within 1% of the value.<br />
<br />
I also quickly threw this job together, so I didn't test for extremely large integers or any edge cases.<br />
<br />
Here's a simple job that demonstrates how it works.<br />
<div>
<br /></div>
<div>
<br /></div>
<div>
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">static</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">KW_DecToFrac</span>(Args _args)
{
<span style="color: #888888;">// Create a function that accepts these two parameters</span>
real _real = <span style="color: #6600ee; font-weight: bold;">0.45</span>;
real _accuracy = <span style="color: #6600ee; font-weight: bold;">0.01</span>;
<span style="color: #333399; font-weight: bold;">int</span> sign = _real < <span style="color: #6600ee; font-weight: bold;">0</span> ? -<span style="color: #6600ee; font-weight: bold;">1</span> : (_real == <span style="color: #6600ee; font-weight: bold;">0</span> ? <span style="color: #6600ee; font-weight: bold;">0</span> : <span style="color: #6600ee; font-weight: bold;">1</span>);
real maxError;
System.Decimal d;
<span style="color: #333399; font-weight: bold;">int</span> n;
<span style="color: #333399; font-weight: bold;">int</span> lower_n = <span style="color: #6600ee; font-weight: bold;">0</span>;
<span style="color: #333399; font-weight: bold;">int</span> lower_d = <span style="color: #6600ee; font-weight: bold;">1</span>;
<span style="color: #333399; font-weight: bold;">int</span> middle_n;
<span style="color: #333399; font-weight: bold;">int</span> middle_d;
<span style="color: #333399; font-weight: bold;">int</span> upper_n = <span style="color: #6600ee; font-weight: bold;">1</span>;
<span style="color: #333399; font-weight: bold;">int</span> upper_d = <span style="color: #6600ee; font-weight: bold;">1</span>;
<span style="color: #333399; font-weight: bold;">int</span> z;
<span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">f</span>(<span style="color: #333399; font-weight: bold;">int</span> _N, <span style="color: #333399; font-weight: bold;">int</span> _D)
{
info(strFmt(<span style="background-color: #fff0f0;">"%1/%2"</span>, _N, _D));
}
_real = abs(_real);
maxError = sign == <span style="color: #6600ee; font-weight: bold;">0</span> ? _accuracy : _real * _accuracy;
d = System.Math::Floor(_real);
n = System.Decimal::ToInt32(d);
_real -= n;
<span style="color: #008800; font-weight: bold;">if</span> (_real < maxError)
{
f(sign * n, <span style="color: #6600ee; font-weight: bold;">1</span>);
<span style="color: #008800; font-weight: bold;">return</span>;
}
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #6600ee; font-weight: bold;">1</span> - maxError < _real)
{
f(sign * (n+<span style="color: #6600ee; font-weight: bold;">1</span>), <span style="color: #6600ee; font-weight: bold;">1</span>);
<span style="color: #008800; font-weight: bold;">return</span>;
}
<span style="color: #008800; font-weight: bold;">while</span> (<span style="color: #008800; font-weight: bold;">true</span>)
{
z++;
middle_n = lower_n + upper_n;
middle_d = lower_d + upper_d;
<span style="color: #008800; font-weight: bold;">if</span> (middle_d * (_real + maxError) < middle_n)
{
upper_n = middle_n;
upper_d = middle_d;
}
<span style="color: #008800; font-weight: bold;">else</span> <span style="color: #0066bb; font-weight: bold;">if</span> (middle_n < (_real - maxError) * middle_d)
{
lower_n = middle_n;
lower_d = middle_d;
}
<span style="color: #008800; font-weight: bold;">else</span>
{
f((n * middle_d + middle_n) * sign, middle_d);
<span style="color: #008800; font-weight: bold;">return</span>;
}
}
info(<span style="background-color: #fff0f0;">"Done"</span>);
}
</pre>
</div>
</div>
Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.com12tag:blogger.com,1999:blog-3546795444588179926.post-29224597857410922018-04-04T15:00:00.000-07:002018-04-04T15:00:21.556-07:00[#MsDyn365FO] How to adjust your DeployablePackages cleanup durationMicrosoft automatically cleans up the "DeployablePackages" folder for data older than 30 days on your Dynamics 365 for Finance and Operations, Enterprise Edition machine if you are using the LCS servicing flows.<br />
<br />
If you prefer to keep less data, such as 10 days, you can add the following registry key to <span style="background-color: #edeff2; color: #343a41; font-family: "segoe ui westeuropean" , "segoe ui" , "segoe ui emoji" , , "blinkmacsystemfont" , "roboto" , "helvetica neue" , sans-serif; font-size: 15px;">HKLM:\SOFTWARE\Microsoft\Dynamics\Deployment</span> :<br />
<span style="background-color: #edeff2; color: #343a41; font-family: "segoe ui westeuropean" , "segoe ui" , "segoe ui emoji" , , "blinkmacsystemfont" , "roboto" , "helvetica neue" , sans-serif; font-size: 15px;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvrfHD1ZrbGxRvRDQmpYHxvfFpjP2vyaI-GV0XmIl94cBO1jone8PtGW4ETQkpF0qHOHkXsamCkZWu7yI2hRKk9b44MooKfDE33dP2WO1p-qpGVwuNU4na0ntwzf_SbLdrSQ6UfVzj8pyy/s1600/2018-04-04_14-55-57.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="107" data-original-width="545" height="123" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvrfHD1ZrbGxRvRDQmpYHxvfFpjP2vyaI-GV0XmIl94cBO1jone8PtGW4ETQkpF0qHOHkXsamCkZWu7yI2hRKk9b44MooKfDE33dP2WO1p-qpGVwuNU4na0ntwzf_SbLdrSQ6UfVzj8pyy/s640/2018-04-04_14-55-57.png" width="640" /></a></div>
<span style="background-color: #edeff2; color: #343a41; font-family: "segoe ui westeuropean" , "segoe ui" , "segoe ui emoji" , , "blinkmacsystemfont" , "roboto" , "helvetica neue" , sans-serif; font-size: 15px;"><br /></span>
Or copy & paste the below into a *.reg file, and you can add it that way:<br />
<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;">Windows Registry Editor Version 5.00
<span style="color: #008800; font-weight: bold;">[</span><span style="color: #007020;">HKEY_LOCAL_MACHINE</span><span style="color: #008800; font-weight: bold;">\SOFTWARE\Microsoft\Dynamics\Deployment]</span>
<span style="color: #0000cc;">"CutoffDaysForCleanup"</span><span style="color: #333333;">=</span><span style="background-color: #fff0f0;">"10"</span>
</pre>
</div>
<br />
<br />
See Yammer thread <a href="https://www.yammer.com/dynamicsaxfeedbackprograms/threads/1031302928" target="_blank">here </a>for Microsoft's comments.Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.com1tag:blogger.com,1999:blog-3546795444588179926.post-91873107673586491842018-01-02T12:26:00.000-07:002018-01-02T12:26:27.539-07:00How to see when AOS service was started/stopped with PowerShell for AX with 1 line of code.I often need to see when an AOS was stopped for various reasons, and scanning the event viewer can be a hassle. Running this simple 1-line PowerShell script will give you that information.<br />
<br />
You can also use this script as a guide to run other PowerShell scripts to search the event log for specific text.<br />
<br />
<blockquote class="tr_bq">
Get-WinEvent -ErrorAction SilentlyContinue -FilterHashtable @{logname='system'; StartTime=(((get-date).AddDays(-30).Date)); EndTime=(((get-date).AddDays(1).Date)); id=7036} -MaxEvents 10000 | ? {$_.Message -like '*Microsoft Dynamics AX Object Server*'}</blockquote>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhz3HBRuptTBkg-UhoCycQK6w74JL_IExuVYD1GeUkjM0YltzyyYRShkI-np9E5qyw6H65RnIkx4N_txQR3gjV-eUTAr347Utyevb6fyDapyd2Mo1u3fa1HXOZpny08NhpEn3eE8puvZh3i/s1600/Powershell.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="262" data-original-width="1600" height="104" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhz3HBRuptTBkg-UhoCycQK6w74JL_IExuVYD1GeUkjM0YltzyyYRShkI-np9E5qyw6H65RnIkx4N_txQR3gjV-eUTAr347Utyevb6fyDapyd2Mo1u3fa1HXOZpny08NhpEn3eE8puvZh3i/s640/Powershell.png" width="640" /></a></div>
Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.com2tag:blogger.com,1999:blog-3546795444588179926.post-11599881122499236852017-08-22T13:41:00.000-07:002017-08-22T13:43:27.768-07:00Job to export AX 2012 label file in Dynamics 365 FOEE format for easy movementI am maintaining an ISV solution across AX 2012 and Dynamics 365 for Finance and Operations, Enterprise Edition, and when there is development in one, porting those changes to the other can be a hassle.<br />
<br />
If I create a label in Dynamics AX 2012, exactly creating it in D365 isn't straight forward/simple.<br />
<br />
I quickly wrote this simple job to export a label to a format that can be easily imported into Dynamics 365. I simply looked at how D365 label text is stored and inferred this, so I haven't done extensive testing, but it seems to work fine for several hundred labels when comparing via WinMerge what my job outputs vs what D365 contains.<br />
<br />
<br />
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: Consolas, "Courier New", Courier, Monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #a31515; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
<pre class="csharpcode"><span class="kwrd">static</span> <span class="kwrd">void</span> AlexOnDaxExportLabelToD365(Args _args)
{
#File
str labelFileId = <span class="str">'QUA'</span>;
str language = <span class="str">'en-us'</span>;
Filename labelFilenameD365 = @<span class="str">'C:\Temp\AlexLabel.label.txt'</span>;
LabelId labelId;
LabelString labelString;
LabelDescription labelDescription;
Set setLabelIds;
SetEnumerator se;
SysLabelFileReader labelFileReader;
TextIo textIo;
SysLabelFile labelFile = SysLabelFile::newLanguageModule(language, labelFileId);
<span class="kwrd">if</span> (!Label::flush(labelFileId, language))
<span class="kwrd">throw</span> error(strFmt(<span class="str">"Unable to flush label %1 in language %2"</span>, labelFileId, language));
<span class="kwrd">new</span> FileIOPermission(labelFilenameD365, <span class="str">'W'</span>).assert();
<span class="rem">// This just create the file if it doesn't exist</span>
textIo = <span class="kwrd">new</span> TextIo(labelFilenameD365, #IO_Write, #utf8Format);
textIo.write(<span class="str">''</span>);
textIo = <span class="kwrd">null</span>;
<span class="rem">// We output the file somewhere </span>
<span class="kwrd">if</span> (labelFile.toFile(labelFilenameD365, <span class="kwrd">true</span>))
{
labelFileReader = SysLabelFileReader::newFileClient(labelFilenameD365);
<span class="kwrd">if</span> (labelFileReader)
{
setLabelIds = labelFileReader.labelIds();
}
}
<span class="kwrd">if</span> (!(setLabelIds && labelFileReader))
<span class="kwrd">throw</span> error(<span class="str">"Unable to get label"</span>);
textIo = <span class="kwrd">new</span> TextIo(labelFilenameD365, #IO_Write, #utf8Format);
se = setLabelIds.getEnumerator();
while (se.moveNext())
{
labelId = se.current();
labelString = labelFileReader.labelText(labelId);
labelDescription = labelFileReader.labelDescription(labelId);
<span class="rem">// There must be a value</span>
<span class="kwrd">if</span> (!labelString)
labelString = <span class="str">' '</span>;
<span class="kwrd">if</span> (labelDescription)
textIo.write(labelId + <span class="str">'='</span> + labelString + <span class="str">'\n'</span> + <span class="str">' ;'</span> + labelDescription);
<span class="kwrd">else</span>
textIo.write(labelId + <span class="str">'='</span> + labelString);
}
textIo.write(<span class="str">''</span>); <span class="rem">// Write ending CR</span>
textIo = <span class="kwrd">null</span>;
CodeAccessPermission::revertAssert();
info(strFmt(<span class="str">"Finished converting %1 to Dynamics 365 for Operations label file"</span>, labelFilenameD365));
}</pre>
Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.com174tag:blogger.com,1999:blog-3546795444588179926.post-46356884640373471062017-08-16T11:58:00.000-07:002017-08-16T11:58:46.328-07:00How to find previously used addresses or other older records in Valid Time State Tables for Date Effective Data in Microsoft Dynamics 365 or AXIn Dynamics (AX/365) there is a concept of <a href="https://msdn.microsoft.com/en-us/library/gg861781.aspx" target="_blank">"Valid Time State Tables" that contain date effective data</a>. In this post, you'll find code to list all the previous addresses tied to an individual record.<br />
<br />
If you are not familiar with this type of data, the simplest example to wrap your head around is postal addresses. If you are, just skip the next paragraph.<br />
<br />
Let's say you send an order/invoice to a customer at <b>123 South St</b> on 1/1/2017. Then a few months later, the customer moves locations to <b>456 North Ave</b> and you update their address in Dynamics. All is good so far. Then for some reason you need to reprint the 1/1/2017 invoice...well that address record for <b>123 South St</b> still exists in the database, but it's "ValidTo" is in the past. This way you have the historical addresses.<br />
<br />
This sample job below takes an address and loops through the older versions of that address. This method can be used to seek any data in valid time state tables though.<br />
<br />
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: Consolas, "Courier New", Courier, Monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #a31515; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
<pre class="csharpcode">
<span class="kwrd">static</span> <span class="kwrd">void</span> AlexOnDAXFindOldAddresses(Args _args)
{
CustTable custTable = CustTable::find(<span class="str">"ZZZZ"</span>);
LogisticsPostalAddress logisticsPostalAddress;
LogisticsPostalAddress logisticsPostalAddressOld;
utcDateTime utcMinVal = DateTimeUtil::minValue();
utcDateTime utcMaxVal = DateTimeUtil::maxValue();
<span class="rem">// Active address</span>
logisticsPostalAddress = CustTable.postalAddress();
info(<span class="str">"Current: "</span> + logisticsPostalAddress.Address);
setPrefix(<span class="str">"Previous Addresses"</span>);
<span class="rem">// This will loop through the inactive addresses in order</span>
while select validTimeState(utcMinVal, utcMaxVal) logisticsPostalAddressOld
order by ValidTo desc
where logisticsPostalAddressOld.Location == logisticsPostalAddress.Location &&
logisticsPostalAddressOld.RecId != logisticsPostalAddress.RecId
{
info(strFmt(<span class="str">"%1 [%2-%3]"</span>,
logisticsPostalAddressOld.Address,
logisticsPostalAddressOld.ValidFrom,
logisticsPostalAddressOld.ValidTo));
}
}</pre><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1vnaPCbhs8MC5nBwqOSfYQ4V0Dv1aRuTHgGX8aiq_P7Su6XPR3XV5A4VswKKj9X5ON4cWkYB3Mh7UHAt9V8REACv0Z4kCcTRdAvYEEG1MBsgS-OCctDqN8DxwWvXwsAMNv0IGqZoZ8uq1/s1600/2017-08-16_11-56-42.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="211" data-original-width="607" height="222" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1vnaPCbhs8MC5nBwqOSfYQ4V0Dv1aRuTHgGX8aiq_P7Su6XPR3XV5A4VswKKj9X5ON4cWkYB3Mh7UHAt9V8REACv0Z4kCcTRdAvYEEG1MBsgS-OCctDqN8DxwWvXwsAMNv0IGqZoZ8uq1/s640/2017-08-16_11-56-42.png" width="640" /></a></div>
<br />Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.com8tag:blogger.com,1999:blog-3546795444588179926.post-2482907434256677172017-05-26T12:08:00.000-07:002017-05-26T12:13:57.282-07:00How to rename a D365 virtual machine, link it to LCS, and optionally join it to a domain - Dynamics 365 for Finance and Operations, Enterprise editionWhenever I get a new D365 virtual machine, I need to rename it, link it to LCS, and join it to our domain. I kept forgetting what I did, so I wrote it down here to share.<br />
<br />
I rename it because there are multiple copies of the VM on the same network, and joining to a domain should be obvious all of the benefits there.<br />
<br />
So here are the steps that I perform to quickly do this, and if anyone has any other steps to add/modify, please let me know and I'll update the post. Follow carefully as each step is important.<br />
<br />
<br />
<ol>
<li>Connect to the VM, provision yourself (as usual)</li>
<li>Go to Control Panel>System and Security>Security, click "Change Settings", and rename the machine to something unique.<div class="separator" style="clear: both; text-align: center;">
<a href="http://imgur.com/3r2qPiE.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://imgur.com/3r2qPiE.jpg" data-original-height="396" data-original-width="800" height="197" width="400" /></a></div>
</li>
<li>Restart VM</li>
<li>Open Reporting Services Configuration Manager and connect to "localhost" or whatever you named your machine, and change the Database server so that it connects<div class="separator" style="clear: both; text-align: center;">
<a href="http://imgur.com/ndKnbKM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://imgur.com/ndKnbKM.jpg" data-original-height="516" data-original-width="800" height="257" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
</li>
<li>Open SQL Management Studio by doing "<b><u style="background-color: yellow;">Run As Administrator</u></b>", as the Local Admins security group is added but not the local administrator user. Connect to SQL.</li>
<li>Run these commands to get the name SQL thinks it is and the name you've used<br /><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">select</span><span style="font-family: "consolas"; font-size: 9.5pt;"> </span><span style="color: magenta; font-family: "consolas"; font-size: 9.5pt;">@@SERVERNAME</span><span style="font-family: "consolas"; font-size: 9.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal">
<span style="color: blue; font-family: "consolas"; font-size: 9.5pt; line-height: 107%;">Select</span><span style="font-family: "consolas"; font-size: 9.5pt; line-height: 107%;"> </span><span style="color: magenta; font-family: "consolas"; font-size: 9.5pt; line-height: 107%;">serverproperty</span><span style="font-family: "consolas"; font-size: 9.5pt; line-height: 107%;">(</span><span style="color: red; font-family: "consolas"; font-size: 9.5pt; line-height: 107%;">'ServerName'</span><span style="font-family: "consolas"; font-size: 9.5pt; line-height: 107%;">)</span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://imgur.com/hYHHvar.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://imgur.com/hYHHvar.jpg" data-original-height="253" data-original-width="393" height="257" width="400" /></a></div>
<o:p></o:p></li>
<li>Copy the old machine name and new machine name and replace it in these SQL commands and execute them<br /><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style="color: green; font-family: "consolas"; font-size: 9.5pt;">--Run
this with the updated names</span><span style="font-family: "consolas"; font-size: 9.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style="color: maroon; font-family: "consolas"; font-size: 9.5pt;">sp_dropserver</span><span style="font-family: "consolas"; font-size: 9.5pt;"> </span><span style="color: red; font-family: "consolas"; font-size: 9.5pt;">'MININT-S45GUTR'</span><span style="font-family: "consolas"; font-size: 9.5pt;">;</span><span style="font-family: "consolas"; font-size: 9.5pt;"> </span><span style="color: green; font-family: "consolas"; font-size: 9.5pt;">--Old Name</span><span style="font-family: "consolas"; font-size: 9.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">GO</span><span style="font-family: "consolas"; font-size: 9.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<br /></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style="color: maroon; font-family: "consolas"; font-size: 9.5pt;">sp_addserver</span><span style="font-family: "consolas"; font-size: 9.5pt;"> </span><span style="color: red; font-family: "consolas"; font-size: 9.5pt;">'D365QDEVMAIN'</span><span style="font-family: "consolas"; font-size: 9.5pt;">,</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">LOCAL</span><span style="font-family: "consolas"; font-size: 9.5pt;">;</span><span style="font-family: "consolas"; font-size: 9.5pt;"> </span><span style="color: green; font-family: "consolas"; font-size: 9.5pt;">--New Name</span><span style="font-family: "consolas"; font-size: 9.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">GO</span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://imgur.com/6CUm3d4.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://imgur.com/6CUm3d4.jpg" data-original-height="175" data-original-width="443" height="157" width="400" /></a></div>
</li>
<li><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
Restart the machine</div>
</li>
<li><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
In SQL (run as admin), run the steps in <b>Step 6</b> again to verify both return the same new machine name result</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://imgur.com/KtbsthM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://imgur.com/KtbsthM.jpg" data-original-height="281" data-original-width="415" height="270" width="400" /></a></div>
</li>
<li><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
(Optional) The following steps are the optional LCS/Domain steps. Create a project in LCS that your D365 for Operations (or whatever it's called at the time of reading this) VM will connect to.</div>
</li>
<li><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
(Optional) Download the LCS diagnostic installer under the "System Diagnostic" tile</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://imgur.com/4G5NmI8.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://imgur.com/4G5NmI8.jpg" data-original-height="417" data-original-width="405" height="320" width="310" /></a></div>
</li>
<li><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
(Optional) Extract and run Setup. Choose "Create a new certificate" and enter whatever into the prefix. I usually just do the machine name.</div>
</li>
<li><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
(Optional) This creates a certificate in the same directory as the installer, upload the certificate back into LCS under the same tile, then continue with the installer after it has been uploaded.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://imgur.com/2u6RKmJ.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://imgur.com/2u6RKmJ.jpg" data-original-height="441" data-original-width="800" height="352" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
</li>
<li><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
(Optional) For the account/password I put in MachineName\Administrator and the administrator password. If you choose to use the local admin, it's important that you type the newly created machine name you chose or it doesn't always work.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://imgur.com/DK0JW8m.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://imgur.com/DK0JW8m.jpg" data-original-height="399" data-original-width="517" height="246" width="320" /></a></div>
</li>
<li><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
(Optional) There should now be a new icon on your desktop to launch the LCS diagnostic utility. Run this.</div>
</li>
<li><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
(Optional) Put in the environment name and server name with your newly chosen name and put "AxDB" for the database name. Then click the buttons at the bottom of the tool in sequence.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://imgur.com/G9rFyq4.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://imgur.com/G9rFyq4.jpg" data-original-height="800" data-original-width="605" height="400" width="301" /></a></div>
</li>
<li><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
(Optional) When you get to step #3, your window may white-out and clear. Just choose the drop-down at the top under "Environment Name" and re-select your environment</div>
</li>
<li><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
(Optional) Click "Generate Command" to get a copy/paste command that you can set up a scheduled task for so that LCS gets regular data. Copy the command and close the window. Mine was:<br />
<br />
"C:\Program Files\Microsoft Dynamics Lifecycle Services System Diagnostic Service\LCSDiagFXCollector.exe" "-Collect" "D365QDEVMAIN" "1"</div>
</li>
<li><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
(Optional) Open "Task Scheduler" and create a new task and choose "Run whether user is logged on or not" and I choose "Run with highest privileges"</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://imgur.com/Gtt5kf6.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://imgur.com/Gtt5kf6.jpg" data-original-height="607" data-original-width="800" height="302" width="400" /></a></div>
</li>
<li><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
(Optional) Choose the Triggers tab and setup a daily trigger (or whatever you want)</div>
</li>
<li><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
(Optional) Choose the "Actions" tab, click New, and paste the entire command in the program/script window and click ok. It will prompt you to automatically fix it so just click yes.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://imgur.com/GK0Sn1V.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://imgur.com/GK0Sn1V.jpg" data-original-height="675" data-original-width="739" height="292" width="320" /></a></div>
</li>
<li><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
(Optional) Click OK to save the task and enter your user/password so that it can store it to run the task</div>
</li>
<li><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
(Optional) Go back to LCS and under the same "System Diagnostic" tile, click on the "Environments" tab and verify your new environment is there and data is uploaded</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://imgur.com/HDr4G2S.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://imgur.com/HDr4G2S.jpg" data-original-height="211" data-original-width="800" height="105" width="400" /></a></div>
</li>
<li><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
(Optional) Finally join it to your domain and restart.</div>
</li>
</ol>
<div>
<br /></div>
<div>
And you are done!</div>
Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.com40tag:blogger.com,1999:blog-3546795444588179926.post-90005165685640842202017-05-18T10:40:00.002-07:002017-05-18T10:40:36.777-07:00How to programmatically add menu items to favorites menu via X++ in Dynamics AXThe favorites menu is a bit unusual in AX in the way you need to add to it. Most of the way it works appears to be Kernel level, but through some TreeNode usage you can add items to it.<br />
<br />
This will add the "SalesTable" menu item to your favorites.<br />
<br />
<!-- code formatted by http://manoli.net/csharpformat/ -->
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: Consolas, "Courier New", Courier, Monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #a31515; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
<br />
<pre class="csharpcode"><span class="kwrd">static</span> <span class="kwrd">void</span> JobAddToFavorites(Args _args)
{
TreeNode treeNode;
TreeNode menuToAdd = TreeNode::findNode(<span class="str">@"\Menu Items\Display\SalesTable"</span>);
TreeNodeIterator iterator;
UserMenuList userMenu;
Menu menuNode;
treeNode = infolog.userNode();
iterator = treeNode.AOTiterator();
treeNode = iterator.next();
<span class="kwrd">if</span> (treeNode)
{
userMenu = treeNode;
<span class="rem">// find 'My Favorites' user menu; </span>
treeNode = userMenu.AOTfindChild(<span class="str">"@SYS95713"</span>);
<span class="rem">// Note menuNode is a different object than userMenu</span>
menuNode = treeNode;
menuNode.addMenuitem(menuToAdd);
}
}</pre>
<br />
Another table to take note of is SysPersonalization if you're looking at doing this for multiple users. I haven't dug into this deeply, but this code snippet should get you started with what you may want to do.Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.com3tag:blogger.com,1999:blog-3546795444588179926.post-77871800729312992962017-05-05T12:30:00.002-07:002017-05-05T12:39:17.448-07:00How to remove the default filter controls on a ListPane in AX 2012When you create a ListPage, the kernel automatically adds a FormFilterPaneControl with some filtering options. Many think this can't be removed or hidden, but it can!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4t2B0nml7an9SPrZqNvg2ccjiVO_MHG1sX1gqiGjDlz76pgu2gQvTH-HOcPs1FqoaNPNagL9woz_jYfmpgY67XIxaA2H14rhVaKR6kGvvjqwlMqTINcAqS1VN6fNo-YluCtFxyqW8DxLP/s1600/2017-05-05_12-24-06.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="96" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4t2B0nml7an9SPrZqNvg2ccjiVO_MHG1sX1gqiGjDlz76pgu2gQvTH-HOcPs1FqoaNPNagL9woz_jYfmpgY67XIxaA2H14rhVaKR6kGvvjqwlMqTINcAqS1VN6fNo-YluCtFxyqW8DxLP/s640/2017-05-05_12-24-06.png" width="640" /></a></div>
<br />
<br />
It is added during the run method's super() call by the kernel, so using this code on the ListPage you can remove it. The caveat is if you are using the ListPage FormTemplate, it's not possible because you're not able to override the run method.<br />
<br />
The last closing comment I'll add is I don't know if the kernel expects the control to be there later on and if this can cause any issues or not. I just was curious if I could get it to go away.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: Consolas, "Courier New", Courier, Monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #a31515; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
<br />
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">void</span> run()
{
<span class="kwrd">int</span> i;
FormControl formControl;
super();
<span class="kwrd">for</span> (i=1; i<=element.design().controlCount(); i++)
{
formControl = element.design().controlNum(i);
<span class="kwrd">if</span> (formControl <span class="kwrd">is</span> FormFilterPaneControl)
{
element.design().removeControl(formControl.id());
}
}
}</pre>
<pre class="csharpcode">
</pre>
<pre class="csharpcode">
</pre>
Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.com6tag:blogger.com,1999:blog-3546795444588179926.post-39499420309720086632017-04-17T10:42:00.000-07:002017-04-17T10:43:41.185-07:00Address Validation in Dynamics AX - QuAAX<div class="separator" style="clear: both; text-align: center;">
</div>
I wanted to talk about a new product for address validation and discovery in AX called QuAAX (Quality Addressing for AX), powered by Experian Data Quality. It's more than a simple "is this address valid or not" type of program and allows for address discovery, quick entry, and some fuzzy operations. It also works internationally with 200+ countries supported.<br />
<br />
<br />
<div style="text-align: center;">
<i><b><span style="color: red;">Disclaimer</span></b>: I worked on this product.</i></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://axmentor.com/solutions/products/quality-addressing-for-ax/" target="_blank"><img border="0" height="128" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj880SKHWKIZa4ZhJr7JnkG4g6E4ydrZIMRLk5U3yA1wNt3g6HWAmQBtNLz2IAw9E6C36aFUqI6utBkEyjlr1tm-4Bz_4b7ABuKIgdvEhgE5kyiIkRxIkSurRltKTCKdldjZD_4ZghapMT5/s320/QuAAX_blk_org_ExperianAdd.png" width="320" /></a></div>
<br />
<br />
Addresses in AX can be a headache. Between data migrations from years of different systems, order imports from external sources, and user entry error you can end up with a mess of postal address records that you have varying degrees of confidence in. This is where QuAAX can help solve many of those issues.<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoniTeWY6MrDwLrGSztRIeZMj593ROyglNgUBR9ZYrLBGib2L1AfBa4TrT8PCieWC5KSyLm-zAqcizlYWv-HUyml6qb6K2oyrhU0uNCYskNLLOEj956t3c1hw9Evhr3CQnOxnDfNDXThSs/s1600/QuAAXDemo.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoniTeWY6MrDwLrGSztRIeZMj593ROyglNgUBR9ZYrLBGib2L1AfBa4TrT8PCieWC5KSyLm-zAqcizlYWv-HUyml6qb6K2oyrhU0uNCYskNLLOEj956t3c1hw9Evhr3CQnOxnDfNDXThSs/s1600/QuAAXDemo.gif" /></a></div>
<br />
The code is almost entirely X++ and lives in AX, which makes desired customization easy and provides transparency. It's designed to be an easy install via model file with a few overlayered objects to merge.<br />
<br />
It is powered by Experian Data Quality web services, so for the configuration you simply put in your Auth Token and set a few minor settings. This means you don't need to update any on-premise software. It also back-fills related tables, so no need to create new zip-codes and it can automatically complete zip+4 codes.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCsiWmdrEiH1MkJGezwzIvzyu_lVh6P41NB9XMs8TMnZqW_MOmYw06hPeQJNSRFj9vCKG8Ymw1q3hGfI_13RMtkL1TtAAoGP4dLkqd1jzvq8QLNPNGrs6Hl_qeU4hIf9UcVcEqZ_Iuvdu7/s1600/Config.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="177" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCsiWmdrEiH1MkJGezwzIvzyu_lVh6P41NB9XMs8TMnZqW_MOmYw06hPeQJNSRFj9vCKG8Ymw1q3hGfI_13RMtkL1TtAAoGP4dLkqd1jzvq8QLNPNGrs6Hl_qeU4hIf9UcVcEqZ_Iuvdu7/s320/Config.png" width="320" /></a></div>
<br />
There is a new indicator on the address records throughout the system that visually indicates the status of the address and shortcut buttons to verify addresses.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEha9R2gtFULdgVz-o1G4psVU7UzCstGzINSMryajSf7ewx_BsQ7sqWDgXloMbyMu53UbFaBSRZik09fPPdWkrZfT14V0RASexhk5LzwPSgkW_2kcA9l1KjgM4nCXqK9aohyphenhyphenzaLzmOef-gKr/s1600/GoodBadOverriddenUnknown.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="229" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEha9R2gtFULdgVz-o1G4psVU7UzCstGzINSMryajSf7ewx_BsQ7sqWDgXloMbyMu53UbFaBSRZik09fPPdWkrZfT14V0RASexhk5LzwPSgkW_2kcA9l1KjgM4nCXqK9aohyphenhyphenzaLzmOef-gKr/s320/GoodBadOverriddenUnknown.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
It will automatically create suggestions for validated addresses that are more well formatted.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkSDgS08YQEoHKGD-3XBgLm5N8-qTe-_YI1IUnQ-_uYIrakuXImAj8OYslnuSkzEbmtBGT_gWlzxjgozSfYL5k_qPJXmJBFq3tPqe8E8W4_GuLajpqq92VcpN0MsUOO5du1vOxiJZkNsdy/s1600/UseSuggested.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="289" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkSDgS08YQEoHKGD-3XBgLm5N8-qTe-_YI1IUnQ-_uYIrakuXImAj8OYslnuSkzEbmtBGT_gWlzxjgozSfYL5k_qPJXmJBFq3tPqe8E8W4_GuLajpqq92VcpN0MsUOO5du1vOxiJZkNsdy/s640/UseSuggested.gif" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
When you have an address that is close to correct, it will automatically jump into the edit view with the parts it was able to verify and ask for user input. An example is this address (401 B St, San Diego, CA 92101) where I forgot to enter the suite #. It prompts me to enter it and provides acceptable ranges of input.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiewz1teTEPEqzIgPdhqnkfy0kP1fh7Nr4DF-LErVNGkpw1mWywR2tp3j_2AoJzETFjs8MLwkn1JfJHvBYhr1Bj7Nekhp7lgVo7GFU_ByfKgKv-DJ2Mya_nRrEH6ZB8gUcWYp7Qc1lEMkU0/s1600/MissingSteDemo.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="348" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiewz1teTEPEqzIgPdhqnkfy0kP1fh7Nr4DF-LErVNGkpw1mWywR2tp3j_2AoJzETFjs8MLwkn1JfJHvBYhr1Bj7Nekhp7lgVo7GFU_ByfKgKv-DJ2Mya_nRrEH6ZB8gUcWYp7Qc1lEMkU0/s640/MissingSteDemo.gif" width="640" /></a></div>
<br />
There is a fancy engine used for keying in new addresses that lets you very quickly enter data and also suggests inputs as you type.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrAg2F1FqBbBOzh7LSX3DWJPj7aD3WCOML_Qvs0vVBk1q_GkdupCLW8Ky54wqhUlbSkaXE9KJ15w8KH1a_3cv7mtJVh9Shmtb2yGUK8E0nMLghszyjDvn4_K019MwIoOqJtvabQaknwrVI/s1600/TypedownDemo.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="396" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrAg2F1FqBbBOzh7LSX3DWJPj7aD3WCOML_Qvs0vVBk1q_GkdupCLW8Ky54wqhUlbSkaXE9KJ15w8KH1a_3cv7mtJVh9Shmtb2yGUK8E0nMLghszyjDvn4_K019MwIoOqJtvabQaknwrVI/s640/TypedownDemo.gif" width="640" /></a></div>
<br />
It also has a bulk processing engine and simple API, so you can perform cleanup on your legacy data or perform validation calls on new addresses input from external sources.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCiTZPefsyE8u6b39FCsmIHbxKIz7cwuyA3k0uL4ktaKPqgI23z2hf2cCkJviTY1Nk3snSCf7oUB9W71ZqTSB35FMcIOKDxLfGXOByEKSFU0qOtmTxF1KqvJfgWyuQ-wn-0GYo5vbqTAy7/s1600/AddressQueue.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="171" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCiTZPefsyE8u6b39FCsmIHbxKIz7cwuyA3k0uL4ktaKPqgI23z2hf2cCkJviTY1Nk3snSCf7oUB9W71ZqTSB35FMcIOKDxLfGXOByEKSFU0qOtmTxF1KqvJfgWyuQ-wn-0GYo5vbqTAy7/s400/AddressQueue.png" width="400" /></a></div>
<br />
Some final comments. Right now it's supported for AX 2012 and it's coming soon to Dynamics 365 for Operations. There are plenty more features I wasn't able to cover in this post such as lat/long, address type indicator (residential vs commercial), and more.<br />
<br />
<span style="font-size: large;">More information can be found here: <a href="http://axmentor.com/solutions/products/quality-addressing-for-ax/">http://axmentor.com/solutions/products/quality-addressing-for-ax/</a></span><br />
<br />
As always, happy DAX'ing!<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.com7tag:blogger.com,1999:blog-3546795444588179926.post-40150732857666562382017-03-14T09:57:00.000-07:002017-03-14T09:58:32.499-07:00New features (CDS Integrations) and some clarity on Common Data Services (CDS) and how it will work in the Dynamics 365 Sphere of productsFor the last year how the Common Data Services (CDS) will actually work and play in the Dynamics 365 sphere of products has been a fairly gray area. It has been often promised that "<i>it just works"</i>, without providing any details to what is going on behind the scenes. Hopefully I'll be able to provide some grain of clarity on that.<br />
<br />
<b>The following is still under development by Microsoft and hasn't been officially announced, but it's what I've gathered from speaking with the various product members.</b><br />
<br />
<blockquote class="tr_bq">
<b><i>How does the Common Data Model get filled by the CDS? - </i><span style="color: red;">Microsoft is building 1st class integrations</span></b></blockquote>
<blockquote class="tr_bq">
<b><br /></b><b><i>Is it flow? - </i><span style="color: red;">No</span></b></blockquote>
<br />
<b>New configuration section - "Integrations":</b><br />
<b><br /></b>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6_qSi8LKLPWJfkf6ilh6xVPfkdhu7ZsoDaW8NNJufmy_-sHCcRX0elg_IfhYH_TS0bmoxYNr9eggnuQKQhDnGFN66KA60NgqjiJegEhJU7q8s7Q7Gf0jEorra2aI_cHDNt3FlGjpzdAH0/s1600/2017-03-14_8-59-48.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="341" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6_qSi8LKLPWJfkf6ilh6xVPfkdhu7ZsoDaW8NNJufmy_-sHCcRX0elg_IfhYH_TS0bmoxYNr9eggnuQKQhDnGFN66KA60NgqjiJegEhJU7q8s7Q7Gf0jEorra2aI_cHDNt3FlGjpzdAH0/s400/2017-03-14_8-59-48.png" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
So this doesn't yet exist yet, but there is supposed to come a new section in the PowerApps Admin Center where you can configure your environment integrations with the Common Data Service. It's also important to note that it lives in the PowerApps Admin Center for now only because they haven't come up with a better place, even though it doesn't seem to make total sense to me.<br />
<br />
So things like:<br />
<br />
<ol>
<li>Dynamics 365 for Sales (CRM) to</li>
<li>Common Data Services to</li>
<li>Dynamics 365 for Operations (AX)</li>
</ol>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgx_cIYC3D4ZdLRXMLFtfyHDSFPEs9lXvo0eaNPQhikuthyphenhyphenyPcqb2YS5eNnRKa6qdkwVWdz-AQKCFP-xkHUg2wVCr3kp5769UmCi_TuPPWKQoViky2XFhBSVxZkJzBZ4HNhBdRdbaWrjIxZ/s1600/20170313_140117.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgx_cIYC3D4ZdLRXMLFtfyHDSFPEs9lXvo0eaNPQhikuthyphenhyphenyPcqb2YS5eNnRKa6qdkwVWdz-AQKCFP-xkHUg2wVCr3kp5769UmCi_TuPPWKQoViky2XFhBSVxZkJzBZ4HNhBdRdbaWrjIxZ/s640/20170313_140117.jpg" width="640" /></a></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsIPCvIkU0XLSjX1d7XMcpZX38MOUyw22s61VAxQleICbZ7RJlIEYOpNsg5OLNIDtgpGuW9U0HgEKI8A6a9mimJLeAKTtKiWNg2S4SHbQZdPCubC6iY49hxZsctIc4cLuK81KsP414DMt1/s1600/20170313_140213.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsIPCvIkU0XLSjX1d7XMcpZX38MOUyw22s61VAxQleICbZ7RJlIEYOpNsg5OLNIDtgpGuW9U0HgEKI8A6a9mimJLeAKTtKiWNg2S4SHbQZdPCubC6iY49hxZsctIc4cLuK81KsP414DMt1/s640/20170313_140213.jpg" width="640" /></a></div>
<div>
<br /></div>
<div>
This order is important because "<i>you have to crawl before you can walk" </i>and Microsoft's first goal is to go from Sales => CDS => Operations. Eventually, they'll go both ways.</div>
<div>
<br /></div>
<div>
<b>Flow Templates:</b></div>
<div>
<b><br /></b></div>
<div>
If you're like me and tried to figure it out on your own, you may have stumbled upon some pre-configured <b>Flow Templates </b>that might fit the need:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGmfC-Yhc2OikTfUPOtTIVtzKio0BgtMuLCryXX7oo7_DEK7KEIebwCHlWRIvarag34TYk4g5F7SNwn0kGpqx_f2eOanIez32-zDrvCS33iWa60ySMT9XnhSMHIjr1sTzwOZJJTC3UoMjV/s1600/CRM+Flow+AX.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGmfC-Yhc2OikTfUPOtTIVtzKio0BgtMuLCryXX7oo7_DEK7KEIebwCHlWRIvarag34TYk4g5F7SNwn0kGpqx_f2eOanIez32-zDrvCS33iWa60ySMT9XnhSMHIjr1sTzwOZJJTC3UoMjV/s320/CRM+Flow+AX.png" width="317" /></a></div>
<blockquote class="tr_bq">
<b><i>How are flow templates different than integrations?</i></b></blockquote>
<div>
<b><i><br /></i></b></div>
<div>
Integrations to the Common Data Service will be more robust and "first class" integrations by Microsoft for bulk data moving and syncing, while Flow Templates are for purpose built, row-by-row needs.</div>
<div>
<br /></div>
<blockquote class="tr_bq">
<b><i>What technologies do integrations use under the hood?</i></b></blockquote>
The integrations use a combination of Data Import Export Framework (DIXF), OData, and <b>M-Engine</b> which sits under Power Query. These allow the integration to push bulk amounts of data between the systems on an unspecified syncing schedule.<br />
<br />
This is an exciting time as these technologies are bleeding edge and new things are expected to release very soon! As always, happy DAX'ing! Or D365'ing?Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.com3tag:blogger.com,1999:blog-3546795444588179926.post-87333010544480545982017-02-15T11:40:00.000-07:002017-02-15T12:00:15.205-07:00Unlimited private agents for Visual Studio Team Services!<div class="tr_bq">
In January Microsoft announced via e-mail <b><span style="background-color: yellow;">good</span> </b>changes to Build & Release Private Agents. They introduced the concept of "Private Pipelines" in Visual Studio Team Services.</div>
<div class="tr_bq">
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhA4kRclFivyC_UflAJzEHNgFaC85hV5N8W9L3tV4a3ttVvsBqofmemNQ-ZrnZxhm4J-nI1L_TKUdDOHU-p2qW42SLqdZpBYId9rtH3xrPMcANp1HzNzbS11n33y9oQgevwj-2C3eHEInrA/s1600/AgentsImage.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="276" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhA4kRclFivyC_UflAJzEHNgFaC85hV5N8W9L3tV4a3ttVvsBqofmemNQ-ZrnZxhm4J-nI1L_TKUdDOHU-p2qW42SLqdZpBYId9rtH3xrPMcANp1HzNzbS11n33y9oQgevwj-2C3eHEInrA/s640/AgentsImage.png" width="640" /></a></div>
<br />
<br /></div>
<div class="tr_bq">
<b><u>What are Agents?</u></b></div>
<div class="tr_bq">
An agent is basically a task-runner that you can pass build activities to, such as PowerShell scripts, executables, etc. The agent can either be <a href="https://www.visualstudio.com/en-us/docs/build/concepts/agents/hosted" target="_blank">Hosted</a> (in the cloud on Azure) or <a href="https://www.visualstudio.com/en-us/docs/build/actions/agents/v2-windows" target="_blank">on-premise</a> (installed on your private servers).</div>
<div class="tr_bq">
<br /></div>
<div class="tr_bq">
When you run a build/release process from VSTS, it sends your tasks to an Agent to do your work.</div>
<div class="tr_bq">
<br /></div>
<div class="tr_bq">
<b><u>What's new?</u></b></div>
<div class="tr_bq">
The concept of a "pipeline" is introduced, which is essentially the number of concurrent agents running tasks at the same time. Previously, you were allowed one on-premise agent (for free) and if you wanted more agents on different servers you had to buy additional ones ($15/ea).</div>
<div class="tr_bq">
<br /></div>
<div class="tr_bq">
Now, you can have unlimited on-premise agents! You are given one <a href="https://marketplace.visualstudio.com/items?itemName=ms.build-release-private-pipelines" target="_blank">private</a> and <a href="https://marketplace.visualstudio.com/items?itemName=ms.build-release-hosted-pipelines" target="_blank">hosted</a> pipeline free with your VSTS account. So this means you can still only run operations on one agent at a time unless you buy additional pipelines.</div>
<div class="tr_bq">
<br /></div>
<div class="tr_bq">
<b><u>Why is this a good thing?</u></b></div>
<div class="tr_bq">
If you have Dev/Test/Prod systems, you may want to place an agent on each machine where each has certain privileges and setup your build processes to communicate with each agent. And you may have no need for many concurrent build/release operations, but you want to have your agents (task runners) on different machines. This is VERY convenient. Previously, the work around was to just figure out ways to have your agent run on a single machine and execute operations remotely to the other machines, which you can imagine is a hassle.</div>
<div class="tr_bq">
<br /></div>
<div class="tr_bq">
Here is the full contents of the email:</div>
<blockquote>
<i>Starting later this month and running through the end of February, we will be gradually deploying a change to how we count Build & Release Private Pipelines (previously called Private Agents) in Visual Studio Team Services. It does not change your bill. <br /><br />Up to this point, you have needed a Private Pipeline for each separate private build agent or private release agent that you configure in your Team Services account.</i></blockquote>
<blockquote>
<i>Going forward, you can configure as many private agents as needed in your Team Services account without incurring extra charges. You'll only need as many Private Pipelines as the number of concurrent builds you want to run or releases you want to deploy using your own machines. With this new way of counting Private Pipelines you may be able to purchase fewer Private Pipelines than you do today. </i></blockquote>
<blockquote>
<i>Learn more about the impact of this change on your builds and releases. <br />If you have any questions, please contact us through the Visual Studio Developer Community (http://developercommunity.visualstudio.com) or via customer support (https://www.visualstudio.com/team-services/support/). </i></blockquote>
Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.com3tag:blogger.com,1999:blog-3546795444588179926.post-46253932505603482522016-11-22T14:00:00.002-07:002016-11-22T15:39:35.232-07:00Dynamics 365 for Operations (AX7) leverages Facebook librariesSo a little known thing about Microsoft Dynamics 365 for Operations (AX7) is that the user interface appears to be built on <a href="https://facebook.github.io/react/" target="_blank">Facebook's React JavaScript libraries</a>, specifically React with Addons.<br />
<br />
Hearing Facebook and D365 in the same sentence initially makes me wince a little, but it makes perfect sense. Facebook is in the business of user interface on the web, so why would Microsoft reinvent the wheel for user interface when the engineers at Facebook are leading the way and devoting more resources towards it?<br />
<br />
You can see the React JS files in various locations, such as C:\AOSService\webroot\Scripts\ext\react*.js on a demo VM.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://i.imgur.com/TRVFCUJ.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://i.imgur.com/TRVFCUJ.png" height="221" width="400" /></a></div>
<br />
<br />
If you've tried to create/debug a D3fo custom control using Chrome/FF developer tools and stepped into the JavaScript, you'll eventually see it in the min versions of the React libraries.<br />
<br />
As of writing this, the current version embedded in the Nov 1611 VM is 15.1.0 while the available is v15.3.2.<br />
<br />
So if you're experiencing bugs with some controls, there may be a fix on the horizon.Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.com209tag:blogger.com,1999:blog-3546795444588179926.post-68624861450299156182016-11-22T14:00:00.000-07:002016-11-22T14:00:47.034-07:00Dynamics 365 for Operations (AX7) leverages Facebook librariesSo a little known think about Microsoft Dynamics 365 for Operations (AX7) is that the user interface appears to be built on <a href="https://facebook.github.io/react/" target="_blank">Facebook's React JavaScript libraries</a>, specifically React with Addons.<br />
<br />
Hearing Facebook and D365 in the same sentence initially makes me wince a little, but it makes perfect sense. Facebook is in the business of user interface on the web, so why would Microsoft reinvent the wheel for user interface when the engineers at Facebook are leading the way and devoting more resources towards it?<br />
<br />
You can see the React JS files in various locations, such as C:\AOSService\webroot\Scripts\ext\react*.js on a demo VM.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://i.imgur.com/TRVFCUJ.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://i.imgur.com/TRVFCUJ.png" height="221" width="400" /></a></div>
<br />
<br />
If you've tried to create/debug a D3fo custom control using Chrome/FF developer tools and stepped into the JavaScript, you'll eventually see it in the min versions of the React libraries.<br />
<br />
As of writing this, the current version embedded in the Nov 1611 VM is 15.1.0 while the available is v15.3.2.<br />
<br />
So if you're experiencing bugs with some controls, there may be a fix on the horizon.Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.com3tag:blogger.com,1999:blog-3546795444588179926.post-67262779287663183972016-05-04T13:32:00.000-07:002016-05-04T13:44:11.742-07:00The better way to detect when multiple records are selectedThere are some instances when you want to know when multiple records are marked on a form. An example would be if you wanted a button to be enabled <b>only</b> when more than 1 record was selected.<br />
<br />
You can make a button disabled when more than 1 record is selected, but not the other way around.<br />
<br />
As far as I can tell, the way the grid functions is it stores an <i>Array</i> object of the cursor positions of the marked records. Below are the two ways I've seen to solve this problem. Method #2 is more common, but Method #1 seems more efficient to me as you're only interacting with the <i>Array</i> and not traversing the datasource's table buffer.<br />
<br />
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: Consolas, "Courier New", Courier, Monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #a31515; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
<br />
<pre class="csharpcode"> FormDataSource fds = salesTable.dataSource();
<span class="rem">// Method 1</span>
<span class="rem">// The grid stores an array of marked records, and this</span>
<span class="rem">// will return only the index, which is all that is needed</span>
<span class="kwrd">if</span> (fds.recordsMarked().lastIndex() > 1)
info(<span class="str">"Multiple records selected"</span>);
<span class="kwrd">else</span>
info(<span class="str">"1 or 0 records selected"</span>);
<span class="rem">// Method 2</span>
<span class="rem">// This will traverse the datasources buffer</span>
fds.getFirst(<span class="kwrd">true</span>);
<span class="kwrd">if</span> (fds.getNext())
info(<span class="str">"Multiple records selected"</span>);
<span class="kwrd">else</span>
info(<span class="str">"1 or 0 records selected"</span>);
<span class="rem">// Enabling/Disabling button in one line</span>
myButton.enabled(SalesTable_ds.recordsMarked().lastIndex() > 1);</pre>
<br />
<span style="background-color: yellow;"><u>And how to enable/disable a button in one line</u>:
</span><br />
<br />
<pre class="csharpcode"> <span class="rem">// Enabling/Disabling button in one line</span>
myButton.enabled(SalesTable_ds.recordsMarked().lastIndex() > 1);</pre>
Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.com2tag:blogger.com,1999:blog-3546795444588179926.post-12653925815246615372015-12-03T13:09:00.003-07:002015-12-03T13:09:43.022-07:00Some notes on Dynamics AX 2012 and the registry<br />
<ul>
<li>[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\AOS60$01]</li>
<ul>
<li>Windows service configurations</li>
</ul>
<li>HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Dynamics Server</li>
<ul>
<li>AOS Server(s) configurations</li>
</ul>
<li>HKEY_CURRENT_USER\Software\Microsoft\Dynamics\</li>
<ul>
<li>When a user opens the client config, this registry key is created and it stores their configurations which take priority over HKLM</li>
</ul>
<li>HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Dynamics</li>
<ul>
<li>These are the client config settings for the machine that are used when HKCU settings aren't present.</li>
</ul>
</ul>
Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.com4tag:blogger.com,1999:blog-3546795444588179926.post-6210847733521003172015-11-10T14:12:00.001-07:002015-11-10T14:12:26.442-07:00CacheDataMethod (AX2012 feature) property vs CacheAddMethodA someone little known feature of AX 2012 is a new property called "CacheDataMethod".<br />
<br />
Previously, when you wanted to improve performance by caching your display/edit methods, you would place a line of code like this after the super() in the datasource's init() method:<br />
<br />
<blockquote class="tr_bq">
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: Consolas, "Courier New", Courier, Monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #a31515; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
<pre class="csharpcode"><span class="kwrd">this</span>.cacheAddMethod(tableMethodStr(CustTable, MyDisplayMethod));</pre>
</blockquote>
<br />
In AX 2012, you can just change the "CacheDataMethod" property on the object without adding code. I prefer this method where possible mainly because it keeps everything packaged together and I don't have to intermingle my code with base code.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4vApSMcJ143WzKMCZ7G7kctNL794g71clOWWSSGhNef93rUhEUMHS6S6eCgmJzl-CrWRCEYcAgO6Caq2ayVuRyK6GAo0c4d7rd_3RbHoE3zO5OqXDKiISmjviyvmvv7TuwMlh94sWUjrs/s1600/11-10-2015+2-05-09+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4vApSMcJ143WzKMCZ7G7kctNL794g71clOWWSSGhNef93rUhEUMHS6S6eCgmJzl-CrWRCEYcAgO6Caq2ayVuRyK6GAo0c4d7rd_3RbHoE3zO5OqXDKiISmjviyvmvv7TuwMlh94sWUjrs/s640/11-10-2015+2-05-09+PM.png" width="296" /></a></div>
<br />Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.com3tag:blogger.com,1999:blog-3546795444588179926.post-72435116636205121852015-11-09T14:09:00.000-07:002015-11-09T19:02:55.666-07:00The better way to pass containers between objects/forms using the Args() class, and not by converting to a stringIf you need to pass a container between objects/forms using the Args class, don't convert it to a string and then back, use <b>parmObject() and ContainerClass()</b>! I see many suggestions about converting it to a string, which can have much more unpredictable results and is not as versatile.<br />
<br />
You wrap your container in the class <b>ContainerClass()</b> and then unwrap it at the other end.<br />
<br />
Make your call like this:<br />
<blockquote class="tr_bq">
<pre class="csharpcode">args.parmObject(<span class="kwrd">new</span> ContainerClass([<span class="str">"Real container"</span>, 1234, <span class="str">"Not con2str container"</span>]));</pre>
</blockquote>
And retrieve it like this:<br />
<blockquote class="tr_bq">
<pre class="csharpcode">containerClass = element.args().parmObject() <span class="kwrd">as</span> ContainerClass;
myContainer = containerClass.value();</pre>
</blockquote>
<br />
To test this, create a form (Form1) and overwrite the init method and put in this code:<br />
<br />
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: Consolas, "Courier New", Courier, Monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #a31515; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
<blockquote class="tr_bq">
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">void</span> init()
{
ContainerClass containerClass;
container conValue;
<span class="kwrd">if</span> (!(element.args() && element.args().parmObject() && element.args().parmObject() <span class="kwrd">is</span> ContainerClass))
<span class="kwrd">throw</span> error(<span class="str">"@SYS22539"</span>);
super();
containerClass = element.args().parmObject() <span class="kwrd">as</span> ContainerClass;
conValue = containerClass.value();
info(strFmt(<span class="str">"The container contains '%1'"</span>, con2Str(conValue)));
}</pre>
</blockquote>
<br />
Then create a Job and put in this code:<br />
<br />
<blockquote class="tr_bq">
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: Consolas, "Courier New", Courier, Monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #a31515; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
<pre class="csharpcode"><span class="kwrd">static</span> <span class="kwrd">void</span> JobForm1(Args _args)
{
Args args;
FormRun formRun;
args = <span class="kwrd">new</span> Args();
args.name(formStr(Form1));
args.parmObject(<span class="kwrd">new</span> ContainerClass([<span class="str">'Real containers'</span>, 1234, <span class="str">'Not con2str containers'</span>]));
formRun = classFactory.formRunClass(args);
formRun.init();
formRun.run();
formRun.wait();
}</pre>
</blockquote>
<br />
And then run the job!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipzLfWF3Gi66zcpa4Pr1072u4pS3Nb_NScIroXzHvd7A6Z7rH1zvcYHNnNfcAUe_UrYV5W8-SfGjBjRRY8NRzEdVpbH0q_27r0S_PJvVhyphenhyphenweVvsNNj_gXLolJVhZrJjp1IBcQTq8gB8Q7F/s1600/11-9-2015+2-03-41+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipzLfWF3Gi66zcpa4Pr1072u4pS3Nb_NScIroXzHvd7A6Z7rH1zvcYHNnNfcAUe_UrYV5W8-SfGjBjRRY8NRzEdVpbH0q_27r0S_PJvVhyphenhyphenweVvsNNj_gXLolJVhZrJjp1IBcQTq8gB8Q7F/s320/11-9-2015+2-03-41+PM.png" width="274" /></a></div>
<br />Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.com5tag:blogger.com,1999:blog-3546795444588179926.post-3940357510692546302015-10-28T12:25:00.000-07:002015-10-28T12:25:01.295-07:00How to create a self-elevating PowerShell script that will run as administrator every timeOften there are various build processes or other automated tasks that run via PowerShell and need to be run as administrator. If you forget to run it as administrator, it won't work, and you don't always know.<br />
<br />
I came across a great blog post by <a href="https://social.msdn.microsoft.com/profile/benjamin%20armstrong/" target="_blank">Ben Armstrong</a> that I have to share, where he's created a block of code you just prefix to the beginning of your PowerShell script that will re-launch it as administrator if it is not. Check his post out here:<br />
<br />
<a href="http://blogs.msdn.com/b/virtual_pc_guy/archive/2010/09/23/a-self-elevating-powershell-script.aspx">http://blogs.msdn.com/b/virtual_pc_guy/archive/2010/09/23/a-self-elevating-powershell-script.aspx</a><br />
<br />
Here's a screenshot of the PowerShell code in case his blog goes down:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjv2LsJ_CN7SFfQnFYlugxIpXMDfrgx3CQoGlESlhtiLaEoH8ZxTr5Q-bvVtudIZqEoT5uIkmc2ljC_LbRFhkclR7f-VzTFgCgt1gjdQRN0Xbdz3Y6w-65QCD4AvObViiKPsHMv8VQft3p8/s1600/SelfElevatingPowershell.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="552" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjv2LsJ_CN7SFfQnFYlugxIpXMDfrgx3CQoGlESlhtiLaEoH8ZxTr5Q-bvVtudIZqEoT5uIkmc2ljC_LbRFhkclR7f-VzTFgCgt1gjdQRN0Xbdz3Y6w-65QCD4AvObViiKPsHMv8VQft3p8/s640/SelfElevatingPowershell.png" width="640" /></a></div>
<br />Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.com3tag:blogger.com,1999:blog-3546795444588179926.post-84615899601686567342015-10-13T13:30:00.001-07:002015-10-14T10:41:02.936-07:00Without any customization, how to incrementally compile the CIL from the command lineWith Dynamics AX 2012, you can start an incremental CIL compile from the command line (or Power Shell) without any customization. This is useful if you have any automated processes that import XPOs frequently and you don't want to constantly build the full CIL.<br />
<br />
Create an XML file with this data:<br />
<br />
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: Consolas, "Courier New", Courier, Monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #a31515; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
<br />
<pre class="csharpcode"><span class="kwrd"><?</span><span class="html">xml</span> <span class="attr">version</span><span class="kwrd">="1.0"</span> ?<span class="kwrd">></span>
<span class="kwrd"><</span><span class="html">AxaptaAutoRun</span>
<span class="attr">exitWhenDone</span><span class="kwrd">="true"</span>
<span class="attr">version</span><span class="kwrd">="6.2"</span>
<span class="attr">logFile</span><span class="kwrd">="C:\AxaptaAutorun.log"</span><span class="kwrd">></span>
<span class="kwrd"><</span><span class="html">CompileIL</span> <span class="attr">incremental</span><span class="kwrd">="true"</span> <span class="kwrd">/></span>
<span class="kwrd"></</span><span class="html">AxaptaAutoRun</span><span class="kwrd">></span></pre>
<br />
Then save it in a place that is accessible from the AOS service account. I saved it as "<b>C:\IncrementalCIL.xml</b>" on the AOS machine.<br />
<br />
Then run this command, subbing in for your environment:<br />
<br />
<b><span style="font-family: Courier New, Courier, monospace; font-size: large;">"C:\Program Files (x86)\Microsoft Dynamics AX\60\Client\Bin\Ax32.exe" \\MyNetworkShare\AOS.axc -startupcmd=autorun_C:\IncrementalCIL.xml</span></b>
<br />
<b><br /></b>
Some notes about the XML. The <i style="font-weight: bold;">version</i> attribute must not be greater than your system's build, which can be found from calling <b><i>xInfo::releaseVersion()</i></b>.<br />
<br />
There are a TON more <i style="font-weight: bold;">autorun</i> features available, and you can use the following links or just dig into <b><i>\Classes\SysAutoRun</i></b>.<br />
<br />
More information can be found at:<br />
<br />
<ul>
<li><a href="https://msdn.microsoft.com/en-us/library/sysautorun.aspx">https://msdn.microsoft.com/en-us/library/sysautorun.aspx</a></li>
<li><a href="https://msdn.microsoft.com/en-us/library/aa569641.aspx">https://msdn.microsoft.com/en-us/library/aa569641.aspx</a></li>
</ul>
<div>
<br /></div>
<br />
<br />
<br />Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.com2tag:blogger.com,1999:blog-3546795444588179926.post-20887104352356726342015-09-10T14:55:00.002-07:002015-10-28T10:18:56.173-07:00How to export all private or shared projects with or without project definitions from a specified layerI often have to switch development machines, and when I do, I lose all of my private or shared projects. This is a good way to backup your projects and/or their definitions.<br />
<br />
<br />
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: Consolas, "Courier New", Courier, Monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #a31515; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
<pre class="csharpcode">
<span class="kwrd">static</span> <span class="kwrd">void</span> AKExportProjects(Args _args)
{
#AotExport
TreeNodeIterator tni;
ProjectNode projectNode;
<span class="kwrd">int</span> exportFlag;
Dialog dialog = <span class="kwrd">new</span> Dialog();
DialogField folderName;
DialogField projectDefinitionOnly;
DialogField exportFromLayer;
DialogField projectType;
UtilEntryLevel layer;
dialog.addText(<span class="str">"This will export all projects (shared or private) that exist in a selected model."</span>);
projectType = dialog.addFieldValue(enumStr(ProjectSharedPrivate), ProjectSharedPrivate::ProjPrivate);
projectDefinitionOnly = dialog.addField(extendedTypeStr(NoYesId), <span class="str">'Project Definition Only'</span>);
folderName = dialog.addField(extendedTypeStr(FilePath));
exportFromLayer = dialog.addField(enumStr(UtilEntryLevel), <span class="str">'Projects from layer'</span>);
dialog.run();
<span class="kwrd">if</span> (dialog.closedOk())
{
<span class="kwrd">if</span> (!folderName.value())
<span class="kwrd">throw</span> error(<span class="str">"Missing folder"</span>);
exportFlag = #export;
<span class="kwrd">if</span> (projectDefinitionOnly.value())
exportFlag += #expProjectOnly;
layer = exportFromLayer.value();
<span class="kwrd">switch</span> (projectType.value())
{
<span class="kwrd">case</span> ProjectSharedPrivate::ProjPrivate:
tni = SysTreeNode::getPrivateProject().AOTiterator();
<span class="kwrd">break</span>;
<span class="kwrd">case</span> ProjectSharedPrivate::ProjShared:
tni = SysTreeNode::getSharedProject().AOTiterator();
<span class="kwrd">break</span>;
}
projectNode = tni.next() <span class="kwrd">as</span> ProjectNode;
while (projectNode)
{
<span class="kwrd">if</span> (projectNode.AOTLayer() == layer)
projectNode.treeNodeExport(folderName.value() + <span class="str">'\\' + projectNode.name() + '</span>.xpo', exportFlag);
projectNode = tni.next() <span class="kwrd">as</span> ProjectNode;
}
}
<span class="kwrd">else</span>
warning(<span class="str">"No action taken..."</span>);
}</pre>Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.com1tag:blogger.com,1999:blog-3546795444588179926.post-22936814004663491682015-08-03T12:22:00.001-07:002015-08-04T12:06:10.719-07:00How to check if a Base Enum has a valid valueBase enums can use integer assignment to be set, but you can set it 0 to any positive valid integer up to 255 inclusive, and that does not mean it's a valid enum.<br />
<br />
Take for example the base enum "<b>ABC</b>" (\Data Dictionary\Base Enums\ABC). You can assign ABC=555, and it will store an integer value of 255 with no issue.<br />
<br />
To check if an enum value is valid, you can use this method:<br />
<br />
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: Consolas, "Courier New", Courier, Monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #a31515; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
<pre class="csharpcode">
<span class="kwrd">static</span> boolean checkABCEnum(ABC _abc)
{
<span class="kwrd">return</span> <span class="kwrd">new</span> DictEnum(enumNum(ABC)).value2Symbol(_abc));
}</pre>
<br />
Here is a sample job that will demonstrate how this can be an issue:<br />
<br />
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: Consolas, "Courier New", Courier, Monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #a31515; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
<pre class="csharpcode">
<span class="kwrd">static</span> <span class="kwrd">void</span> CheckIfEnumIsValid(Args _args)
{
<span class="rem">// Possible enum values 0, 1, 2, 3</span>
ABC abcValid, abcInvalid;
<span class="rem">// Valid enum</span>
abcValid = ABC::C;
info(strFmt(<span class="str">"%1, %2"</span>, enum2int(abcValid), abcValid));
<span class="rem">// Invalid enum, but integer assignment works and is stored</span>
abcInvalid = 555;
info(strFmt(<span class="str">"%1, %2"</span>, enum2int(abcInvalid), abcInvalid));
<span class="kwrd">if</span>(<span class="kwrd">new</span> DictEnum(enumNum(ABC)).value2Symbol(abcValid))
info(strFmt(<span class="str">"Enum with type %1 and integer value %2 (%3) is valid"</span>, typeOf(abcValid), enum2int(abcValid), abcValid));
<span class="kwrd">else</span>
error(strFmt(<span class="str">"Enum with type %1 and value %2 is invalid"</span>, typeOf(abcValid), enum2int(abcValid)));
<span class="kwrd">if</span>(<span class="kwrd">new</span> DictEnum(enumNum(ABC)).value2Symbol(abcInvalid))
info(strFmt(<span class="str">"Enum with type %1 and integer value %2 (%3) is valid"</span>, typeOf(abcInvalid), enum2int(abcInvalid), abcInvalid));
<span class="kwrd">else</span>
error(strFmt(<span class="str">"Enum with type %1 and value %2 is invalid"</span>, typeOf(abcInvalid), enum2int(abcInvalid)));
<span class="rem">/*</span>
<span class="rem"> Output:</span>
<span class="rem"> 3, C</span>
<span class="rem"> 4, </span>
<span class="rem"> Enum with type Enum and integer value 3 (C) is valid</span>
<span class="rem"> Enum with type Enum and value 4 is invalid</span>
<span class="rem"> */</span>
}</pre>Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.com2tag:blogger.com,1999:blog-3546795444588179926.post-25736062381496005232015-06-03T13:40:00.000-07:002015-06-03T15:06:17.965-07:00How to export/import your MorphX VCS settings and historyWhen using MorphX for version control, sometimes you need to restore a backup of a database, and you don't want to lose all of your check in/out history. I wrote this job to export and import your MorphX VCS settings.<br />
<br />
Use at your own risk, but it's worked fine for me.<br />
<br />
Enjoy!<br />
<br />
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: Consolas, "Courier New", Courier, Monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #a31515; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
<br />
<pre class="csharpcode"><span class="kwrd">static</span> <span class="kwrd">void</span> AKBackupMorphXVCData(Args _args)
{
SysDataExport sysDataExport;
SysDataImport sysDataImport;
Dialog dialog = <span class="kwrd">new</span> Dialog();
FormBuildRadioControl fbImportExport;
FormRadioControl radioResults;
dialog.addText(<span class="str">"Warning, if you choose Import, this will replace your VCS data and is not reversible!"</span>);
<span class="rem">// Add the radio button, name it anything</span>
fbImportExport = dialog.formBuildDesign().addControl(FormControlType::RadioButton, <span class="str">'RadioButton1'</span>);
fbImportExport.caption(<span class="str">"Choose Import/Export"</span>);
fbImportExport.items(2);
fbImportExport.item(1);
fbImportExport.text(<span class="str">"Export"</span>);
fbImportExport.item(2);
fbImportExport.text(<span class="str">"Import"</span>);
dialog.doInit();
dialog.formRun().design().moveControl(fbImportExport.id());
dialog.run();
<span class="kwrd">if</span> (dialog.closedOk())
{
radioResults = dialog.formRun().control(fbImportExport.id());
<span class="kwrd">if</span> (radioResults.selection() == 0) <span class="rem">// Export</span>
{
sysDataExport = <span class="kwrd">new</span> SysDataExport();
sysDataExport.parmDoNotBypassDefIO(<span class="kwrd">true</span>);
sysDataExport.parmServerAccess(<span class="kwrd">true</span>);
sysDataExport.addTmpExpImpTable(tableNum(SysVersionControlMorphXItemTable), <span class="kwrd">false</span>);
sysDataExport.addTmpExpImpTable(tableNum(SysVersionControlMorphXLockTable), <span class="kwrd">false</span>);
sysDataExport.addTmpExpImpTable(tableNum(SysVersionControlMorphXRevisionTable), <span class="kwrd">false</span>);
sysDataExport.addTmpExpImpTable(tableNum(SysVersionControlParameters), <span class="kwrd">false</span>);
sysDataExport.addTmpExpImpTable(tableNum(SysVersionControlSynchronizeLog), <span class="kwrd">false</span>);
<span class="kwrd">if</span> (sysDataExport.prompt())
{
sysDataExport.parmFiletype(FileType::Binary);
sysDataExport.run();
}
}
<span class="kwrd">else</span> <span class="kwrd">if</span> (radioResults.selection() == 1) <span class="rem">// Import</span>
{
sysDataImport = <span class="kwrd">new</span> SysDataImport();
<span class="kwrd">if</span> (sysDataImport.prompt())
{
sysDataImport.parmLoadAll(<span class="kwrd">true</span>);
sysDataImport.parmInclTablesNotPerComp(<span class="kwrd">true</span>);
sysDataImport.parmFiletype(FileType::Binary);
sysDataImport.run();
versioncontrol.init();
}
}
info(<span class="str">"Done!"</span>);
}
}</pre>
Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.com15tag:blogger.com,1999:blog-3546795444588179926.post-79292641765762385972015-06-03T13:27:00.000-07:002015-06-03T13:27:26.517-07:00Dynamic dialog controls at runtimeThis is a job that demonstrates how to dynamically add controls (specifically radio button) to a dialog at runtime and also change their position and access their values.<br />
<br />
You can use this style in custom advanced UI builders.<br />
<br />
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: Consolas, "Courier New", Courier, Monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #a31515; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
<pre class="csharpcode"><span class="kwrd">static</span> <span class="kwrd">void</span> AKDynamicDialogExample(Args _args)
{
Dialog dialog = <span class="kwrd">new</span> Dialog();
FormBuildRadioControl fbRadioControl;
FormRadioControl radioControl;
<span class="rem">// Add the radio button, name it anything</span>
fbRadioControl = dialog.formBuildDesign().addControl(FormControlType::RadioButton, <span class="str">'RadioButton1'</span>);
<span class="rem">// Set radio basic properties</span>
fbRadioControl.caption(<span class="str">"Test Radio Buttons"</span>);
fbRadioControl.items(2); <span class="rem">// This is needed</span>
fbRadioControl.item(1); <span class="rem">// Switch to first item</span>
fbRadioControl.text(<span class="str">"Item 1"</span>); <span class="rem">// Set first item's text</span>
fbRadioControl.item(2); <span class="rem">// Switch to second item</span>
fbRadioControl.text(<span class="str">"Item 2"</span>); <span class="rem">// Set second item's text</span>
<span class="rem">// This is needed to instantiate the FormRun</span>
dialog.doInit();
<span class="rem">// Just passing one argument moves it UP.</span>
<span class="rem">// So this moves it UP above the "OK/Cancel" buttons created</span>
dialog.formRun().design().moveControl(fbRadioControl.id());
dialog.run();
<span class="kwrd">if</span> (dialog.closedOk())
{
<span class="rem">// You need to access it from the formRun() with the correct</span>
<span class="rem">// form control</span>
radioControl = dialog.formRun().control(fbRadioControl.id());
info(strFmt(<span class="str">"%1"</span>, radioControl.selection()));
}
}</pre>
<br />
<br />
<br />Alex Kwitny (Kwitwell.com)http://www.blogger.com/profile/12458072273859749789noreply@blogger.com1